跳到主要内容

搜索引擎

问题

Elasticsearch 的核心原理是什么?如何实现全文搜索?

面试速答版

Elasticsearch 的核心原理是什么? 核心是倒排索引:传统数据库的索引是「文档 → 内容」,倒排索引是「词 → 出现该词的文档列表」:

  • 写入时走分词(中文用 IK),并为每个词建立倒排表。
  • 查询时同样分词,直接取倒排表同时计算 TF-IDF / BM25 评分进行相关性排序。
  • 底层是 Lucene,分布式架构:Index 拆成多个 Shard(主片)+ Replica(副本),写请求路由到主片,读可以走任意副本。

如何实现全文搜索?

  • 表结构叫 Mapping,类似表 Schema;text 类型会分词,keyword 用于精确匹配/聚合。
  • 常用查询:match(全文、分词后评分)、term(精确、不分词)、bool(多条件组合)、aggs(聚合、类似 GROUP BY)。
  • 进阶场景:高亮、拼写纠错、Suggest 补全、Pinyin 拼音搜索、Vector 语义检索。
  • 轻量替代:中小数据量可用 PostgreSQL tsvector、MeiliSearch、Typesense,运维成本低。

答案

倒排索引

传统数据库是「文档 → 词」的映射,倒排索引是「词 → 文档」的映射。

// 正排索引(MySQL)
Doc1: "React 性能优化指南"
Doc2: "Vue 性能对比分析"

// 倒排索引(Elasticsearch)
"React" → [Doc1]
"Vue" → [Doc2]
"性能" → [Doc1, Doc2]
"优化" → [Doc1]
"分析" → [Doc2]

搜索「性能」时,直接从倒排索引找到 [Doc1, Doc2],无需全表扫描。

Elasticsearch 基础操作

elasticsearch.ts
import { Client } from '@elastic/elasticsearch';

const es = new Client({ node: 'http://localhost:9200' });

// 创建索引(定义 Mapping)
await es.indices.create({
index: 'articles',
body: {
mappings: {
properties: {
title: { type: 'text', analyzer: 'ik_max_word' }, // 中文分词
content: { type: 'text', analyzer: 'ik_smart' },
tags: { type: 'keyword' }, // 不分词,用于精确匹配
publishedAt: { type: 'date' },
},
},
},
});

// 索引文档
await es.index({
index: 'articles',
body: {
title: 'React 18 新特性解析',
content: 'React 18 引入了并发渲染...',
tags: ['react', 'frontend'],
publishedAt: '2024-01-01',
},
});

// 全文搜索
const result = await es.search({
index: 'articles',
body: {
query: {
multi_match: {
query: 'React 性能',
fields: ['title^2', 'content'], // title 权重是 content 的 2 倍
},
},
highlight: {
fields: { title: {}, content: {} }, // 高亮匹配词
},
},
});

轻量替代方案

方案特点适用场景
Elasticsearch功能强大、分布式大规模全文搜索
Meilisearch简单易用、即时搜索中小应用、搜索即服务
Typesense低延迟实时搜索补全
PostgreSQL 全文搜索内置、无额外依赖简单搜索需求
meilisearch.ts
// Meilisearch(更简单的替代方案)
import { MeiliSearch } from 'meilisearch';

const client = new MeiliSearch({ host: 'http://localhost:7700', apiKey: 'xxx' });

// 添加文档
await client.index('articles').addDocuments(articles);

// 搜索(自动处理拼写纠错、同义词)
const results = await client.index('articles').search('React 性能', {
limit: 10,
attributesToHighlight: ['title', 'content'],
});

常见面试问题

Q1: Elasticsearch 和 MySQL LIKE 的区别?

答案

维度ESMySQL LIKE
原理倒排索引全表扫描
中文分词后搜索模糊匹配
性能亿级数据毫秒返回百万级就很慢
相关性自动评分排序

Q2: 分词器是什么?

答案

分词器将文本切分为词条(Term)。如「React 性能优化」:

  • 标准分词器react(按字切分)
  • IK 分词器(中文):react性能优化(按语义切分)

Q3: ES 如何保证和数据库的数据一致?

答案

  1. 双写:写数据库的同时写 ES(有一致性风险)
  2. CDC(Change Data Capture):监听 MySQL Binlog 同步到 ES(推荐)
  3. 消息队列:写数据库后发消息,消费者写 ES

相关链接