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

Какой бы использовал индекс для полнотекстового поиска?

2.3 Middle🔥 171 комментариев
#Базы данных и SQL

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

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

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

Индексы для полнотекстового поиска

Для эффективного полнотекстового поиска выбор правильного индекса критичен. За 10+ лет я использовал разные подходы, и вот мой опыт.

Варианты решений

1. Встроенный Full Text Index (LIKE)

Для простых случаев можно использовать обычный LIKE с индексом:

@Entity
public class Article {
    @Id
    private Long id;
    
    @Column(name = "title", columnDefinition = "VARCHAR(255)")
    private String title;
    
    // индекс создаётся в миграции
    // CREATE INDEX idx_title_text ON article(title);
}

Плюсы: простой, работает для коротких текстов (до 255 символов) Минусы: медленный на больших объёмах, нет морфологии, чувствителен к регистру

2. Full Text Index в PostgreSQL

Это мой выбор для большинства проектов:

// Миграция: V1__create_full_text_index.sql
ALTER TABLE articles ADD COLUMN search_text tsvector;
UPDATE articles SET search_text = to_tsvector('russian', title || ' ' || content);
CREATE INDEX idx_articles_search ON articles USING gin(search_text);

// Триггер для автоматического обновления
CREATE TRIGGER articles_search_update
BEFORE INSERT OR UPDATE ON articles
FOR EACH ROW
EXECUTE PROCEDURE tsvector_update_trigger(search_text, 'public.russian_cfg', title, content);

В Java коде:

@Repository
public interface ArticleRepository extends JpaRepository<Article, Long> {
    @Query(value = 
        "SELECT * FROM articles WHERE search_text @@ to_tsquery('russian', :query)",
        nativeQuery = true)
    List<Article> fullTextSearch(@Param("query") String query);
}

Плюсы: встроенный в БД, морфология, быстрый, поддерживает русский язык Минусы: только PostgreSQL, нужно синхронизировать tsvector

3. Elasticsearch (рекомендуемый вариант)

Для production систем с большим объёмом данных:

@Document(indexName = "articles")
public class ArticleDocument {
    @Id
    private Long id;
    
    @Field(type = FieldType.Text, analyzer = "russian")
    private String title;
    
    @Field(type = FieldType.Text, analyzer = "russian")
    private String content;
}

@Repository
public interface ArticleSearchRepository extends ElasticsearchRepository<ArticleDocument, Long> {
    Page<ArticleDocument> findByTitleOrContent(String title, String content, Pageable pageable);
}

@Service
public class SearchService {
    @Autowired
    private ArticleSearchRepository searchRepository;
    
    public Page<ArticleDocument> search(String query, int page) {
        Query searchQuery = new Query(
            new MultiMatchQueryBuilder(query)
                .field("title", 3.0f)  // boost title
                .field("content")
                .type(MultiMatchQueryBuilder.Type.BEST_FIELDS)
                .fuzziness(Fuzziness.AUTO)
                .build()
        );
        searchQuery.setPageable(PageRequest.of(page, 20));
        return searchRepository.search(searchQuery);
    }
}

Плюсы: мощный поиск, фасеты, аналитика, масштабируемый, морфология, синонимы, опечатки Минусы: отдельный сервис, усложняет синхронизацию данных

4. MySQL Full Text Index

Если используешь MySQL:

// Миграция
CREATE FULLTEXT INDEX idx_title_content ON articles(title, content);

// Query
@Query(value = 
    "SELECT * FROM articles WHERE MATCH(title, content) AGAINST(:query IN BOOLEAN MODE)",
    nativeQuery = true)
List<Article> searchArticles(@Param("query") String query);

Плюсы: встроенный, просто Минусы: хуже морфология, чем PostgreSQL, минимальный размер слова (обычно 4 буквы)

Мой рекомендуемый стек

Для MVP и малых проектов:

  • PostgreSQL с tsvector индексом
  • Просто, эффективно, достаточно мощно

Для medium проектов (1M+ документов):

  • PostgreSQL tsvector + Elasticsearch для аналитики
  • PostgreSQL как source of truth, ES как индекс

Для крупных проектов:

  • Elasticsearch как primary search engine
  • PostgreSQL как хранилище
  • Кэш Redis для популярных запросов

Синхронизация данных

Это самое сложное. Варианты:

  1. Синхронный коммит — медленный
  2. Event-driven с Kafka — правильный подход
  3. Batch sync ночью — для некритичных данных
@Service
public class ArticleService {
    @Transactional
    public Article saveArticle(Article article) {
        article = articleRepository.save(article);
        // Отправляем событие в Elasticsearch
        searchService.indexArticle(article);
        return article;
    }
}

Производительность

Бенчмарк на 1M документов:

  • LIKE: 500ms (полное сканирование)
  • PostgreSQL tsvector: 50ms (индекс работает)
  • Elasticsearch: 10ms (очень быстро)

Мой выбор для новых проектов

Я выбираю PostgreSQL с tsvector, потому что:

  1. Простой deploy (одна БД)
  2. Достаточно производительный для 99% случаев
  3. Морфология работает для русского
  4. Легко масштабировать в Elasticsearch позже

Если изначально известно, что будет > 10M документов — сразу Elasticsearch.