Elasticsearch 核心总结 + 面试题实战(黑马点评项目)

摘要:本文面向 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)

MySQL Elasticsearch 说明
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 速查

  • QueryBuildersmatchQuery(), termQuery(), rangeQuery(), boolQuery()

  • AggregationBuildersterms(), 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. 黑马点评中商户搜索接口怎么写?用到哪些查询?

回答

  • 接口逻辑

    1. 接收关键词、分类、区域、排序、分页等参数。

    2. 构建 bool 查询:

      • must:用 matchname 进行关键词搜索。

      • filter:用 term 筛选分类/区域,用 range 筛选价格/评分,不参与算分,提高性能。

    3. 设置排序(如按评分 score 降序或距离升序)。

    4. 设置高亮,将匹配的关键字用 <em> 标签包裹。

    5. 调用 client.search() 返回结果并解析。

  • 优化 :使用 filter 而不是 must 处理与相关性无关的条件,利用缓存提升查询速度。

Q6. 搜索结果高亮是怎么实现的?

回答

  • DSL 配置

    复制代码
    "highlight": {
      "fields": {
        "name": {
          "pre_tags": "<em>",
          "post_tags": "</em>"
        }
      }
    }
  • Java 解析

    1. SearchHit 中获取 HighlightField 映射。

    2. 根据字段名取出高亮片段:hf.getFragments()[0].string()

    3. 用高亮字符串替换原始文档中的字段值。

  • 黑马点评中商户名称、笔记标题都采用高亮,前端通过 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)实现异步同步。

    1. 商户服务(CRUD)完成后,发送消息到 MQ(如 shop.sync)。

    2. 搜索服务监听消息,解析后通过 Java RestClient 更新 ES 文档。

    3. 对于新增/修改,调用 IndexRequestUpdateRequest;删除则调用 DeleteRequest

  • 保障:利用消息队列的可靠性传输和重试机制,确保最终一致性。

  • 防重:基于消息 ID 或业务 ID 实现幂等,避免重复更新。

Q9. 聚合分析在项目中有什么应用?举例说明。

回答

  • 应用 :搜索页面的筛选条件动态展示

    1. 用户搜索"火锅"后,过滤栏应只展示搜索结果中实际存在的分类和区域。

    2. 使用带相同搜索条件的 terms 聚合,对 categoryarea 字段聚合,获取桶中的 Key 和文档数。

    3. 将聚合结果返回前端渲染筛选条件。

  • 补充 :还可统计各分类的平均消费、评分分布等(使用 stats 子聚合),用于运营报表。

Q10. ES 分页有哪几种方式?黑马点评用哪种?

回答

  • 三种方式

    1. from + size:适用于浅分页,但深度受限(默认限制 10000)。

    2. scroll:生成快照,适合数据导出,不推荐实时搜索。

    3. 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,并结合黑马点评的源码把搜索接口自己实现一遍------动手写一遍,胜过看十遍

相关推荐
IT龟苓膏10 小时前
Redis 数据类型底层原理:SDS、quicklist、intset、skiplist、Bitmap、HyperLogLog 一篇讲清
数据库·redis·skiplist
dllxhcjla13 小时前
Redis
数据库·redis·缓存
牛油果子哥q18 小时前
【Redis分布式高阶篇】Redis分布式锁底层精讲:从裸锁缺陷到Redisson源码级落地,解决超时释放、锁失效、主从漏洞、锁续约难题
数据库·redis·分布式
闪电悠米20 小时前
黑马点评-Redisson-02_reentrant_lock
java·spring boot·redis·分布式·缓存
SilentSamsara20 小时前
缓存策略实战:Redis + Python 多级缓存设计与失效策略
开发语言·redis·python·缓存·性能优化
西安邮电大学21 小时前
Redis四大经典缓存问题
java·redis·后端·其他·面试
超梦dasgg21 小时前
Redisson解锁失败,WatchDog会不会一直续期下去?
java·redis
cheems952721 小时前
[Redis] redis常见命令和String字符串解析
数据库·redis·缓存
Jul1en_21 小时前
【Redis】一文讲透缓存更新策略与缓存预热、穿透、雪崩、击穿
数据库·redis·缓存