| 特性 | Low-Level REST Client | High-Level REST Client | Java API Client |
|---|---|---|---|
| 抽象层级 | 最低,直接发送JSON请求 | 中,提供对象化的API | 最高,完全基于对象,类型安全 |
| 官方状态 | 仍可用,但建议迁移 | 已弃用(Deprecated),不再推荐 | 官方推荐(Recommended) |
| 适用版本 | 所有版本 | ES 7.x 及更早版本 | ES 8.x 及以后版本 |
| 上手难度 | 较难,需手动构建JSON | 简单,API直观 | 中等,需理解新的函数式构建方式 |
黑马旅游案例:
yfeif/hotel-demo: 黑马旅游网案例https://github.com/yfeif/hotel-demo
1.索引库操作
2.文档操作
文档操作根据原请求也能正常处理数据,但是有些解析的时候由于ES版本是8.4.1,依赖是7.12.1导致空指针异常,所以改写为初级的请求。
3.DSL 查询文档
1.DSL 查询分类
🔍 搜索引擎DSL查询的分类(以Elasticsearch/OpenSearch为例)
在搜索领域,DSL查询特指用JSON风格定义的查询语言。其查询可按结构和功能进行分类,最常见的分类方式如下:
一、按查询结构分类
这是最基础的分类方式,将查询分为两大类:
| 类别 | 描述 | 特点 | 常见类型 |
|---|---|---|---|
| 叶子查询 (Leaf Query) | 在单个字段上查找特定值的查询,是查询的最小单元。 | 独立使用,针对特定字段执行搜索。 | 全文检索、精确查询、地理查询等。 |
| 复合查询 (Compound Query) | 包装一个或多个叶子查询或复合查询,用于组合条件或改变其行为。 | 通过逻辑运算(如布尔)组合多个查询条件。 | bool,function_score,dis_max等。 |
二、按查询功能分类
在叶子查询内部,根据功能又可以细分为以下几种:
查询所有:最简单,用于测试,返回索引中的所有文档。例如:
match_all。全文检索查询:对输入文本分词后,在
text类型字段中搜索。例如:match(单字段)、multi_match(多字段)。精确查询:对
keyword、数值、日期等字段进行不分词的精确查找。例如:term(精确值)、range(范围查询)。地理查询:基于经纬度等地理数据进行搜索。例如:
geo_distance(距离)、geo_bounding_box(矩形范围)。专业查询:处理特定需求的查询,如
span query(跨度查询,用于精确位置搜索)、nested query(嵌套查询)、joining query(关联查询)等。
📝 其他分类维度
查询 (Query) vs 过滤 (Filter):
query上下文会计算相关性得分并排序;filter上下文只做筛选,不计算得分,性能更高,常用于缓存。按数据类型:查询方式需匹配字段类型,例如
text字段用全文检索,keyword字段用精确查询。
💎 总结
简单来说,对DSL查询的分类可以从三个层面理解:
广义概念:分为外部DSL和内部DSL。
结构上:分为叶子查询和复合查询。
功能上:叶子查询可进一步分为全文检索、精确查询、地理查询等。
# 查询所有 GET /hotel/_search { "query": { "match_all": {} } }2.全文检索查询
全文检索(Full-Text Search)是搜索引擎和数据库中最核心的查询方式之一,它不是为了进行简单的“字符串匹配”,而是为了进行理解内容含义的“语义”搜索。
💡 什么是全文检索?
简单来说,全文检索的过程就像查字典:
建立索引(查字典前的准备工作):系统会像编写字典的“索引页”一样,扫描文档中的每一个词,为它们建立索引。这个索引会记录每个词出现在哪些文档、以及出现的次数和位置。这个索引结构通常被称为“倒排索引”(Inverted Index)。
执行搜索(根据索引查内容):当你输入关键词查询时,系统不会去原文里逐字扫描,而是直接去“倒排索引”这个目录里快速查找,然后返回包含这些词的文档。
这种“先建目录,再查目录”的方式,让检索效率远高于传统的LIKE模糊匹配。
⚙️ 核心原理:分词与倒排索引
全文检索之所以能“理解”你的搜索,主要依赖两个关键技术:
分词(Analysis):在建立索引和执行搜索时,系统都会用分词器(Analyzer)将文本切分成一个个独立的词条(Term)。例如,“我爱北京天安门”会被切分为“我”、“爱”、“北京”、“天安门”等词条。
倒排索引(Inverted Index):这是全文检索速度的保证。它是一个词条到文档ID的映射表,能快速定位包含特定词条的所有文档。
📋 常见查询类型(以Elasticsearch为例)
在实际使用中,最常见的全文检索查询类型如下:
| 查询类型 | 描述 | 适用场景 |
|---|---|---|
match查询 | 最基础、最核心的全文查询。会对输入进行分词,然后搜索任意一个分词结果。 | 绝大多数常规的搜索场景,如电商、博客的搜索框。 |
match_phrase查询 | 短语匹配。不仅要求所有词出现,还要求它们的顺序和位置必须一致。 | 搜索精确的短语,如“机器学习”、“中华人民共和国”。 |
multi_match查询 | match查询的多字段版本。可以在多个字段(如标题、内容、标签)中同时搜索。 | 不确定关键词在哪个字段,需要在多个字段中综合搜索。 |
query_string查询 | 支持复杂的语法,如布尔逻辑(AND、OR、NOT)、通配符等。 | 提供给有经验的高级用户,进行精确、复杂的搜索。 |
simple_query_string查询 | query_string的简化、更健壮版本。对语法错误容忍度更高,更适合面向普通用户。 | 直接暴露给终端用户的搜索框,避免因用户输入特殊字符导致报错。 |
intervals查询 | 高级匹配。可以对匹配词项的顺序和邻近度(Proximity)进行精细控制。 | 法律、学术等对文本位置关系有严格要求的专业搜索。 |
此外,还有一些特定场景的变种,如match_phrase_prefix常用于搜索框的自动补全(Auto-complete)功能。
💎 总结:全文检索 vs. 精确查询
理解全文检索,关键在于区分它和精确查询(Term Query):
处理方式:全文检索会对输入文本进行分词;而精确查询不会,它将输入作为一个整体。
搜索目标:全文检索搜索的是分词后的词条;精确查询搜索的是未经处理的完整词条。
主要用途:全文检索用于相关性搜索,如Google、百度;精确查询用于过滤,如查找特定ID、状态、精确分类等。
# match查询 GET /hotel/_search { "query": { "match": { "all": "外滩如家" } } } # multi_match查询 GET /hotel/_search { "query": { "multi_match": { "query": "外滩如家", "fields": ["brand","name","business"] } }3.精准查询
在Elasticsearch等搜索引擎的DSL中,精确查询对应的是术语级查询(Term-level Query)。它的核心特点是:查询条件不会被分词器处理,而是作为一个完整的、精确的词条(Term),直接去倒排索引中匹配。
简单来说,全文检索是“模糊理解”,而精确查询是“铁面无私”的一对一比对。
⚙️ 核心机制:不分词 + 精确匹配
精确查询的执行逻辑非常直白:
索引时:文档中的字段值(如果是
keyword类型)会作为一个完整的词条存入倒排索引。查询时:你输入的搜索词不会被分词,直接拿到倒排索引里查找完全相同的词条。
# term查询 GET /hotel/_search { "query": { "term": { "city": { "value": "北京" } } } } # range查询 GET /hotel/_search { "query": { "range": { "price": { "gte": 900, "lte": 2000 } } } }📋 常见精确查询类型
在日常开发中,最常用的精确查询主要有以下几种:
| 查询类型 | 描述 | 示例场景 |
|---|---|---|
term查询 | 最核心的精确匹配,用于查找单个字段的精确值。 | 查询状态为"已完成"的订单;查找age等于25的用户。 |
terms查询 | term的批量版,匹配字段值等于给定数组中任意一个的文档。 | 查找状态为"待支付"或"已取消"的订单。 |
range查询 | 查找字段值在指定数值或日期范围内的文档。 | 查找价格在100-200之间的商品;查找近7天的日志。 |
exists查询 | 查找包含指定字段(且值不为null)的文档。 | 查找所有填写了email字段的用户。 |
term的变体 | 如prefix(前缀匹配)、wildcard(通配符)、regexp(正则) | 查找所有以"A"开头的产品编码。 |
4.地理坐标查询
核心数据类型:geo_point
在进行任何地理查询前,索引中用于存储位置的字段类型必须是geo_point。它支持多种经纬度格式:
对象格式:
"location": {"lat": 41.12, "lon": -71.34}数组格式:
"location": [-71.34, 41.12](注意:GeoJSON格式是经度在前,纬度在后)字符串格式:
"location": "41.12,-71.34"(纬度在前,经度在后)GeoJSON格式:
"location": {"type": "Point", "coordinates": [-71.34, 41.12]}WKT格式:
"location": "POINT (-71.34 41.12)"
📌 主要的地理查询类型
Elasticsearch提供了几种主要的地理查询方式:
1.geo_distance查询:查找“附近”的位置
用于查找距某中心点指定距离内的所有文档。例如,查找(39.90, 116.65)坐标2公里内的所有位置:距离单位可以是km(公里)或m(米)等
# distance 查询 GET /hotel/_search { "query": { "geo_distance": { "distance": "2km", "location": "39.90,116.65" } } }2.geo_bounding_box查询:查找“矩形框”内的位置
用于查找落在指定矩形范围内的所有文档。需要提供矩形的左上角和右下角两个点的坐标。例如,查找以下矩形框内的位置:
GET /my_locations/_search { "query": { "bool": { "filter": { "geo_bounding_box": { "pin.location": { "top_left": { "lat": 40.73, "lon": -74.1 }, "bottom_right": { "lat": 40.01, "lon": -71.12 } } } } } } }5.组合查询
组合查询,在Elasticsearch中特指复合查询(Compound Query),它的核心作用是将多个独立的查询条件组合成一个整体,以实现更复杂的搜索逻辑
GET /hotel/_search { "query": { "function_score": { "query": { "match": { "all": "北京" } }, "functions": [ { "filter": { "term": { "brand": "如家" } }, "weight": 10 } ], "boost_mode": "sum" } } }GET /hotel/_search { "query": { "bool": { "must": [ { "term": { "city": "北京" } } ], "should": [ { "term": { "brand.keyword": "7天酒店" } }, { "term": { "brand.keyword": "速8" } } ], "must_not": [ {"range": {"price": {"lte": 500}}} ], "filter": [{"range": {"score": {"gte": 45}}} ] } } }4.查询结果处理
# 分数按照降序价格按照升序 GET /hotel/_search { "query": { "match_all": {} }, "sort": [ { "score":"desc"}, { "price": "asc"} ] } # 按照经纬度升序 GET /hotel/_search { "query": { "match_all": {} }, "sort": [ { "_geo_distance": {"location": { "lat": 39.911, "lon": 116.395 }, "order": "asc", "unit": "km" } } ] }GET /hotel/_search { "query": { "match": { "all": "如家" } }, "highlight": { "fields": { "all": {}, "name": {"require_field_match": "false"} } } }