← Назад к вопросам

Что такое полнотекстовый поиск?

1.7 Middle🔥 121 комментариев
#DevOps и инфраструктура#Django

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI23 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Полнотекстовый поиск

Полнотекстовый поиск (Full-Text Search, FTS) — это специализированная техника поиска в больших текстовых документах или базах данных, которая позволяет находить документы по отдельным словам или фразам, а не по точному совпадению всей строки.

Основное отличие от обычного LIKE

import sqlite3

conn = sqlite3.connect(':memory:')
cursor = conn.cursor()

cursor.execute('''
    CREATE TABLE articles (
        id INTEGER PRIMARY KEY,
        title TEXT,
        content TEXT
    )
''')

cursor.executemany('INSERT INTO articles VALUES (?, ?, ?)', [
    (1, 'Python Programming', 'Learn Python basics and advanced concepts'),
    (2, 'Web Development', 'Build websites with Django and Flask'),
    (3, 'Data Science', 'Python for data analysis and machine learning'),
])
conn.commit()

# 1. Обычный LIKE — ищет по строке целиком (медленно)
print("LIKE поиск:")
result = cursor.execute(
    "SELECT * FROM articles WHERE content LIKE '%Python%'"
).fetchall()
for row in result:
    print(row)

# 2. Полнотекстовый поиск — быстрее и умнее
print("\nПолнотекстовый поиск (нужна индексация):")

Как работает FTS

1. Индексирование текста

  • Текст разбивается на токены (слова)
  • Убираются стоп-слова (и, или, а, the, a)
  • Применяется стемминг (приведение к корню: "программирование" → "программ")
  • Создаётся обратный индекс: слово → список документов

2. Поиск

  • Запрос также разбивается на токены
  • Ищются совпадения в индексе (очень быстро)
  • Результаты ранжируются по релевантности

SQLite FTS5

import sqlite3

conn = sqlite3.connect(':memory:')
cursor = conn.cursor()

# Создаём таблицу с полнотекстовым поиском
cursor.execute('''
    CREATE VIRTUAL TABLE articles_fts USING fts5(
        title,
        content,
        content='articles',
        content_rowid='id'
    )
''')

# Заполняем индекс
cursor.executemany(
    'INSERT INTO articles_fts(rowid, title, content) VALUES (?, ?, ?)',
    [
        (1, 'Python Programming', 'Learn Python basics and advanced concepts'),
        (2, 'Web Development', 'Build websites with Django and Flask'),
        (3, 'Data Science', 'Python for data analysis and machine learning'),
    ]
)
conn.commit()

# Поиск
print("FTS поиск по одному слову:")
result = cursor.execute(
    "SELECT title, content FROM articles_fts WHERE articles_fts MATCH 'python'"
).fetchall()
for row in result:
    print(row)

# Поиск по фразе
print("\nПоиск по фразе:")
result = cursor.execute(
    'SELECT title FROM articles_fts WHERE articles_fts MATCH \'"data analysis"\' '
).fetchall()
for row in result:
    print(row)

# С ранжированием по релевантности
print("\nС ранжированием:")
result = cursor.execute('''
    SELECT title, rank FROM articles_fts 
    WHERE articles_fts MATCH 'python'
    ORDER BY rank
''').fetchall()
for row in result:
    print(row)

PostgreSQL Full-Text Search

from sqlalchemy import create_engine, text

engine = create_engine('postgresql://...')

with engine.connect() as conn:
    # Создаём tsvector (токенизированный вектор)
    conn.execute(text('''
        CREATE TABLE documents (
            id SERIAL PRIMARY KEY,
            title TEXT,
            body TEXT,
            search_vector tsvector
        )
    '''))
    
    # Заполняем индекс
    conn.execute(text('''
        INSERT INTO documents (title, body, search_vector) VALUES 
        ('Python Guide', 'Learn Python programming', 
         to_tsvector('english', 'Learn Python programming'))
    '''))
    conn.commit()
    
    # Поиск с оператором @@
    result = conn.execute(text(
        "SELECT title FROM documents WHERE search_vector @@ to_tsquery('english', 'python')"
    )).fetchall()
    for row in result:
        print(row)

Elasticsearch для масштабного FTS

from elasticsearch import Elasticsearch

es = Elasticsearch(['http://localhost:9200'])

# Индексирование
es.index(index='articles', id=1, body={
    'title': 'Python Programming',
    'content': 'Learn Python basics and advanced concepts'
})

es.index(index='articles', id=2, body={
    'title': 'Web Development',
    'content': 'Build websites with Django and Flask'
})

# Поиск
results = es.search(index='articles', body={
    'query': {
        'multi_match': {
            'query': 'python',
            'fields': ['title^2', 'content']  # title важнее
        }
    }
})

for hit in results['hits']['hits']:
    print(f"Score: {hit['_score']}, Title: {hit['_source']['title']}")

Сравнение методов

МетодСкоростьМасштабСложностьЯзыки
LIKEМедленно<100KПростоSQL
SQLite FTS5БыстроДо 1MСреднеSQLite
PostgreSQL FTSБыстроДо 10MСреднеPostgreSQL
ElasticsearchОчень быстроМлрд+СложноСпециальный

Стемминг и нормализация

import nltk
from nltk.stem import SnowballStemmer

# Скачиваем ресурсы
nltk.download('punkt')

stemmer = SnowballStemmer('english')

words = ['programming', 'programs', 'programmer', 'programmed']
for word in words:
    print(f"{word}{stemmer.stem(word)}")

# Вывод:
# programming → program
# programs → program
# programmer → program
# programmed → program

Лучшие практики FTS

  1. Выбирай правильный движок

    • Малый объём (<100K) → SQLite FTS5
    • Средний объём (100K-10M) → PostgreSQL FTS
    • Большой объём (>10M) → Elasticsearch/OpenSearch
  2. Оптимизируй стемминг и стоп-слова

    # PostgreSQL
    SELECT * FROM articles 
    WHERE search_vector @@ to_tsquery('english', 'python & web')
    
  3. Кэшируй часто используемые поиски (Redis)

  4. Мониторь производительность через размер индекса

  5. Используй ранжирование для релевантности результатов

Полнотекстовый поиск критичен для любого приложения с большим объёмом текстовых данных. Выбор между SQLite, PostgreSQL и Elasticsearch зависит от масштаба и требований к производительности.

Что такое полнотекстовый поиск? | PrepBro