Какой бы использовал индекс для полнотекстового поиска?
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Индексы для полнотекстового поиска
Для эффективного полнотекстового поиска выбор правильного индекса критичен. За 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 для популярных запросов
Синхронизация данных
Это самое сложное. Варианты:
- Синхронный коммит — медленный
- Event-driven с Kafka — правильный подход
- 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, потому что:
- Простой deploy (одна БД)
- Достаточно производительный для 99% случаев
- Морфология работает для русского
- Легко масштабировать в Elasticsearch позже
Если изначально известно, что будет > 10M документов — сразу Elasticsearch.