摘要:本文面向 Java 开发者及准备后端面试的同学,系统梳理 Elasticsearch 的核心概念、常用 API 与 DSL 查询,并结合黑马点评项目的实际场景整理出 12 道高频面试题及回答思路。全文约 15 分钟读完,建议搭配项目代码一起复习。
一、Elasticsearch 核心总结
1. 为什么用 Elasticsearch
-
MySQL 模糊查询痛点:LIKE 不走索引,数据量大时性能急剧下降;无法处理错别字、拼音、同义词等复杂搜索。
-
ES 优势:基于倒排索引,海量数据搜索性能稳定;支持分词、拼音、同义词等复杂检索;还支持聚合分析。
2. 倒排索引原理
-
正向索引:以文档为主体,通过文档 ID 找到其中包含的词条(或字段值)。典型如 MySQL 的 B+Tree 索引,适合精确查询,但模糊匹配需要全表扫描。
-
倒排索引(es):以词条为主体,先对文档内容分词,建立"词条 → 文档ID列表"的映射,同时记录词频和位置信息。搜索时直接根据词条快速定位文档,性能极高。Elasticsearch 正是基于倒排索引实现全文检索。

-
核心概念:
-
文档(Document):一条 JSON 数据。
-
词条(Term):分词后的最小语义单元。
-
3. 核心概念对比(MySQL vs ES)
| Table | Index | 索引(文档集合) |
| Row | Document | 文档(JSON 格式) |
| Column | Field | 字段 |
| Schema | Mapping | 映射(字段类型、分词等约束) |
| SQL | DSL | JSON 风格的查询语言 |
4. 分词与 IK 分词器
-
分词器作用:创建倒排索引和搜索时,将文本切分为词条。
-
IK 分词器模式:
-
ik_smart:粗粒度,按语义切分。
-
ik_max_word:细粒度,穷尽所有可能组合。
-

-
扩展词典:修改 IKAnalyzer.cfg.xml 添加 ext.dic,放入新词后重启 ES 即可生效。
5. Mapping 映射属性
-
关键字段类型:
text(可分词的字符串)、keyword(精确值,不分词)、integer/long/float/double/boolean/date/object
-
重要属性:
-
index:是否建立索引(默认 true,设为 false 则不可搜索)。
-
analyzer:指定分词器(如 ik_max_word)。
-
6. 索引库 RESTful API
| 创建索引库 | PUT | /索引库名 | 携带 mappings |
| 查询索引库 | GET | /索引库名 | |
| 删除索引库 | DELETE | /索引库名 | |
| 修改索引库 | PUT | /索引库名/_mapping | 只能添加新字段 |
7. 文档 CRUD
| 新增文档 | POST | /索引库名/_doc/文档ID | JSON 文档 |
| 查询文档 | GET | /索引库名/_doc/文档ID | |
| 全量修改 | PUT | /索引库名/_doc/文档ID | 完整 JSON(会覆盖) |
| 局部修改 | POST | /索引库名/_update/文档ID | {"doc": {"字段":"新值"}} |
| 删除文档 | DELETE | /索引库名/_doc/文档ID | |
| 批量操作 | POST | /_bulk | 组合 index/delete/update |
8. Java RestClient 操作
-
初始化:
RestHighLevelClient client = new RestHighLevelClient(
RestClient.builder(HttpHost.create("http://127.0.0.1:9200"))
);
-
索引库操作:client.indices().create(request, RequestOptions.DEFAULT) —— 创建索引;类似的还有 get()(查询)、exists()(判断存在)、delete()(删除)。
-
文档操作:
-
新增:client.index(request, RequestOptions.DEFAULT)
-
查询:client.get(request, RequestOptions.DEFAULT)
-
更新:client.update(request, RequestOptions.DEFAULT)
-
删除:client.delete(request, RequestOptions.DEFAULT)
-
批量:client.bulk(request, RequestOptions.DEFAULT)
-
-
批量导入:分页从 DB 查询数据,每页转成 IndexRequest 加入 BulkRequest。
9. DSL 查询结构
基础查询模板如下,各字段含义详解:
GET /索引库名/_search
{
"query": { … }, // 查询条件(核心)
"from": 0, // 分页起始位置
"size": 10, // 每页条数
"sort": [ … ], // 排序规则
"highlight": { … }, // 高亮配置
"aggs": { … } // 聚合分析
}
-
query:定义筛选条件,支持全文匹配、精确匹配、范围、组合等多种查询。
-
from + size:控制分页,类似 MySQL 的 LIMIT offset, size。
-
sort:指定排序字段与方向。
-
highlight:对关键字高亮标记,返回带标签的片段。
-
aggs:聚合统计,与 query 同级,互不影响。
10. 查询分类

-
叶子查询:
match_all / match(全文检索,分词) / multi_match / term(精确匹配,不分词) / range(范围)
-
复合查询:bool(must/should/must_not/filter),filter 不参与算分,性能更好。
-
算分函数查询:function_score,可人工干预排名(如竞价广告)。
11. 排序、分页、高亮
-
排序:只能对 keyword/数值/日期类型排序,"sort": [ {"price": "desc"} ]
-
分页:from + size,深度分页限制 10000,深分页用 search_after。
-
高亮:highlight 指定字段和标签,结果需从 hit.getHighlightFields() 单独解析。
12. 数据聚合
-
桶聚合:terms(按字段值分组)、date_histogram
-
度量聚合:stats/avg/max/min
-
聚合与 query 同级,size: 0 可不返回文档只返回聚合结果。
-
Java API:AggregationBuilders.terms("名称").field("字段"),结果从 response.getAggregations() 获取。
13. Java RestClient 速查
-
QueryBuilders:matchQuery(), termQuery(), rangeQuery(), boolQuery()
-
AggregationBuilders:terms(), stats()
-
高亮构建:SearchSourceBuilder.highlight()
-
解析结果:response.getHits() → 遍历 SearchHit[],hit.getSourceAsString() 反序列化。
掌握了上面的核心概念之后,我们来看看面试中常见的 Elasticsearch 问题。以下 12 道题全部结合黑马点评项目的实际场景进行拆解——不仅告诉你"怎么答",还会讲清楚"为什么这样设计",帮助你把理论知识真正落地到项目经验中。
二、Elasticsearch 面试题(结合黑马点评项目)
Q1. 黑马点评项目中哪些场景用到了 Elasticsearch?为什么不用 MySQL 模糊查询?
回答:
-
应用场景:
-
商户搜索:用户可根据名称、分类、地址等关键字搜索商户。
-
探店笔记搜索:对笔记标题、内容进行全文检索,支持高亮显示。
-
-
不使用 MySQL 的原因:
-
商户表和笔记表数据量大,模糊查询 LIKE 不走索引,性能极差。
-
ES 基于倒排索引,查询速度快且稳定;支持分词、拼音、同义词等复杂搜索。
-
需要聚合统计(如按分类、区域统计商户数量),MySQL 实现复杂且慢。
-
Q2. 倒排索引是什么?与传统数据库索引有什么区别?
回答:
-
倒排索引:先将文档内容分词得到词条,再建立"词条→文档ID列表"的映射。搜索时直接根据词条快速找到文档ID。
-
与正排索引对比:
-
正排索引(如 MySQL B+Tree):通过 ID 找数据,适合精确查询,模糊查询需全表扫描。
-
倒排索引:通过词条找文档,天然适合全文搜索和模糊匹配,效率极高。
-
-
在黑马点评中,用户输入"海底捞火锅",倒排索引可以快速定位包含"海底捞"、"火锅"等词条的所有商户,无需全表扫描。
Q3. 黑马点评项目中商户索引的 Mapping 是怎么设计的?为什么这样设计?
回答:
-
Mapping 设计(部分字段):
-
id:keyword(精确查询)
-
name:text + ik_max_word(全文搜索)
-
category:keyword(分类过滤、聚合)
-
area:keyword(区域过滤、聚合)
-
price:integer(价格过滤、排序)
-
score:integer(评分排序)
-
location:geo_point(地理坐标搜索)
-
-
设计理由:
-
需要分词的用 text,需要精确匹配/过滤/排序/聚合的用 keyword。
-
使用 ik_max_word 能最大程度匹配用户可能输入的关键字。
-
地理坐标类型支持附近商户搜索。
-
index: false 可设置给不需要搜索的字段(如图片URL),节省索引空间。
-
Q4. IK 分词器有什么作用?如果分不出新词怎么办?
回答:
-
作用:将中文字符串切分成有意义的词条,是倒排索引的核心基础。
-
模式:
-
ik_smart:粗粒度,尽量按语义切分。
-
ik_max_word:细粒度,穷举所有可能词汇。
-
-
新词处理:修改 IKAnalyzer.cfg.xml,添加自定义词典文件(如 ext.dic),将"黑马点评"、"网红店"等新词加入词典,重启 ES 即可生效。
Q5. 黑马点评中商户搜索接口怎么写?用到哪些查询?
回答:
-
接口逻辑:
-
接收关键词、分类、区域、排序、分页等参数。
-
构建 bool 查询:
-
must:用 match 对 name 进行关键词搜索。
-
filter:用 term 筛选分类/区域,用 range 筛选价格/评分,不参与算分,提高性能。
-
-
设置排序(如按评分 score 降序或距离升序)。
-
设置高亮,将匹配的关键字用 <em> 标签包裹。
-
调用 client.search() 返回结果并解析。
-
优化:使用 filter 而不是 must 处理与相关性无关的条件,利用缓存提升查询速度。
Q6. 搜索结果高亮是怎么实现的?
回答:
-
DSL 配置:
"highlight": {
"fields": {
"name": {
"pre_tags": "<em>",
"post_tags": "</em>"
}
}
} -
Java 解析:
-
从 SearchHit 中获取 HighlightField 映射。
-
根据字段名取出高亮片段:hf.getFragments()[0].string()。
-
用高亮字符串替换原始文档中的字段值。
-
黑马点评中商户名称、笔记标题都采用高亮,前端通过 CSS 设置 <em> 颜色即可。

Q7. 如何实现"附近商户"按距离排序?
回答:
-
索引中商户位置字段设为 geo_point。
-
搜索时使用 geo_distance 过滤范围,配合 sort 按距离排序:
"sort": [
{
"_geo_distance": {
"location": { "lat": 40.0, "lon": 116.0 },
"order": "asc",
"unit": "km"
}
}
] -
还可以用 geo_distance 聚合统计不同距离范围内的商户数量。

Q8. 项目中是如何保证 MySQL 与 ES 数据一致性的?
回答:
-
方案:采用 MQ(如 RabbitMQ 或 Kafka)实现异步同步。
-
商户服务(CRUD)完成后,发送消息到 MQ(如 shop.sync)。
-
搜索服务监听消息,解析后通过 Java RestClient 更新 ES 文档。
-
对于新增/修改,调用 IndexRequest 或 UpdateRequest;删除则调用 DeleteRequest。
-
保障:利用消息队列的可靠性传输和重试机制,确保最终一致性。
-
防重:基于消息 ID 或业务 ID 实现幂等,避免重复更新。

Q9. 聚合分析在项目中有什么应用?举例说明。
回答:
-
应用:搜索页面的筛选条件动态展示。
-
用户搜索"火锅"后,过滤栏应只展示搜索结果中实际存在的分类和区域。
-
使用带相同搜索条件的 terms 聚合,对 category 和 area 字段聚合,获取桶中的 Key 和文档数。
-
将聚合结果返回前端渲染筛选条件。
-
补充:还可统计各分类的平均消费、评分分布等(使用 stats 子聚合),用于运营报表。
Q10. ES 分页有哪几种方式?黑马点评用哪种?
回答:
-
三种方式:
-
from + size:适用于浅分页,但深度受限(默认限制 10000)。
-
scroll:生成快照,适合数据导出,不推荐实时搜索。
-
search_after:基于排序值实时分页,推荐用于深度分页。
-
黑马点评中商户列表采用 from + size,因用户一般只浏览前几页;同时限制最大分页深度,防止性能问题。
Q11. ES 如何优化查询性能?
回答:
-
硬件和架构:合理分片、多副本,根据数据量设计集群。
-
索引设计:减少不必要的字段索引(index: false),用 keyword 代替 text 进行过滤。
-
查询优化:
-
用 filter 代替 must,利用缓存。
-
减少返回字段 _source 过滤。
-
避免 wildcard、前缀通配等高性能损耗查询。
-
-
Java 客户端:批量操作使用 BulkRequest,一次发送多条请求,减少网络开销。
Q12. ES 和 MySQL 是如何配合使用的?为什么不是只用一个?
回答:
-
MySQL 负责事务性数据的存储和强一致性操作(如订单、账户),擅长数据安全和 ACID。
-
ES 负责海量数据的搜索、分析和聚合,擅长高性能非结构化查询。
-
黑马点评中:
-
商户基本信息、用户订单由 MySQL 管理。
-
商户搜索、笔记搜索由 ES 负责。
-
通过 MQ 同步,既能保证事务安全又能保证搜索性能,达到优势互补。
-
三、总结
回顾全文,我们从 Elasticsearch 的核心原理(倒排索引、IK 分词、Mapping)出发,到 Java RestClient 的实际操作,再到 黑马点评项目中的面试真题,形成了一条完整的知识链路。
面试小贴士:回答 ES 相关问题时,不要只背概念。面试官更希望听到你结合项目的真实思考——"我们项目里有 XX 场景,遇到了 XX 问题,我选择了 ES 的 XX 特性来解决,最终的 Mapping 是这样设计的……" 这样的回答才有说服力。
如果你想进一步深入,推荐阅读官方文档的 Elasticsearch Definitive Guide,并结合黑马点评的源码把搜索接口自己实现一遍——动手写一遍,胜过看十遍。


