文章目录
- ES分词器ik_smart安装
- ES复杂查询DSL语法详解
-
- match_all匹配所有文档
- 精确匹配
-
- term单字段精确匹配
- terms多字段精确匹配
- range范围查询
- exists:是否存在
- ids:根据一组ID查询
- prefix:前缀匹配
- wildcard:通配符匹配(模糊搜索)
- regexp:正则匹配查询
- fuzzy:支持编辑距离的模糊查询
- [term set:用于解决多值字段中的文档匹配问题](#term set:用于解决多值字段中的文档匹配问题)
- 全文检索
-
- match分词查询
- match_phrase短语查询
- [query_string 支持与或非表达式查询](#query_string 支持与或非表达式查询)
- [simple_query_string 简化的query_string](#simple_query_string 简化的query_string)
- 组合查询BoolQuery
- HighLight高亮
- 地理空间位置查询
- 向量检索
- 实践:实现CSDN文章检索
ES分词器ik_smart安装
shell
# 下载对应版本的分词器
# https://release.infinilabs.com/analysis-ik/stable/
# 查看ES版本
[root@bigdata elasticsearch-9.1.5]# ./bin/elasticsearch --version
warning: ignoring JAVA_HOME=/usr/local/java/jdk1.8.0_421; using bundled JDK
Version: 9.1.5, Build: tar/90ee222e7e0136dd8ddbb34015538f3a00c129b7/2025-10-02T22:07:12.966975992Z, JVM: 25
# 将插件放到plugins目录
[root@bigdata plugins]# pwd
/home/soft/elasticsearch-9.1.5/plugins
[root@bigdata plugins]# ls
elasticsearch-analysis-ik-9.1.5.zip
[root@bigdata plugins]# mkdir analysis-ik
[root@bigdata plugins]# unzip elasticsearch-analysis-ik-9.1.5.zip -d analysis-ik/
[root@bigdata plugins]# rm -f elasticsearch-analysis-ik-9.1.5.zip
# 重新启动ES
[root@bigdata plugins]# su es
[es@bigdata elasticsearch-9.1.5]$ /bin/elasticsearch -d
ES复杂查询DSL语法详解
match_all匹配所有文档
match_all是一个特殊的查询类型,用于匹配索引中的所有文档,而不考虑任何特定的查询条件。
yml
GET /index_name/_search
{
"query": { "match_all": {} },
"size": 10, # 默认返回10条
"from": 3, #从第几条返回。
"sort": [{"id":"asc","create_time":"desc"}], #排序字段
"_source": ["id","name"] # 指定返回字段
}
精确匹配
term单字段精确匹配
搜索内容不经过分词,直接匹配。主要用于结构化数据(ID、状态、标签)等。
适用于未经过分词处理的keyword字段类型。term处理多值字段(数组)的时候,term查询是包含,而不是等于。
yml
GET /index_name/_search
{
"query": {
"term": {
"field.keyword":{
"value": "your_exact_value"
}
}
}
}
# 例子:查询姓名=Huathy的员工
GET /base_info/_search
{
"query": {
"term": {
"cname.keyword":{
"value": "Huathy"
}
}
}
}
# 例子:查询地点=白云的地方。这个例子查询1找不到,而查询2可以找到,是因为address字段进行了分词,keyword是不进行分词匹配,而不带上keyword是和分词的词向量进行匹配。
# 广州白云山: 广州 白云 云山
# 查询1(完整匹配)
GET /employee/_search
{
"query": {
"term": {
"address.keyword": {
"value": "白云"
}
}
}
}
# 查询2(与倒排索引匹配)
GET /employee/_search
{
"query": {
"term": {
"address": {
"value": "白云"
}
}
}
}
# 数组处理
POST /people/_bulk
{"index": {"_id": 1}}
{"name": "小明", "interest": ["跑步", "篮球"]}
{"index": {"_id": 2}}
{"name": "小红", "interest": ["跳舞", "画画"]}
{"index": {"_id": 3}}
{"name": "小丽", "interest": ["跳舞", "唱歌", "跑步"]}
POST /people/_search
{
"query": {
"term": {
"interest.keyword": {"value": "跑步"}
}
}
}
在ES中,term查询对输入不做分词,会将输入作为一个整体,在倒排索引中查找准确的词向量,并且使用相关度得分公式为每个包含改词项的文档进行相关度计算。可以通过Constant Score将查询转为一个filtering来避免算分,并利用缓存,提高性能。
- 将Query转成Filter,忽略TF-IDF计算,避免相关性能开销
- Filter可以有效利用缓存
yml
GET /employee/_earch
{
"query": {
"constant_socre": {
"filter": {
"term": {
"address.keyword": "广州白云山公园"
}
}
}
}
}
terms多字段精确匹配
yml
POST /people/_search
{
"query": {
"terms": {
"interest.keyword": ["画画", "唱歌"]
}
}
}
range范围查询
yml
POST /notes/_search
{
"query": {
"range": {
"create_time": {
"gte": "2025-01-01 00:00:00",
"lte": "2025-12-31 23:59:59"
}
}
}
}
ES支持日期数学表达式,允许在查询和聚合中使用相对时间点。以下是一些场常见的日期数学表达式的示例与解释:
- now:当前时间点
- now-1d:当前时间向前推1天
- now-1w:当前时间向前推1周
- now-1M:当前时间向前推1月
- now-1y:当前时间向前推1年
- now-1h:当前时间向前推1小时
exists:是否存在
yaml
GET /index_name/_search
{
"query" {
"exists": {
"field": "missing_field"
}
}
}
# 示例:文档必须包含remark字段
GET /logs/_search
{
"query" {
"exists": {
"field": "remark"
}
}
}
ids:根据一组ID查询
yaml
GET /index_name/_search
{
"query": {
"ids": {
"values": ["id1","id2"]
}
}
}
prefix:前缀匹配
prefix:会对分词后的term进行前缀搜索。不会对要搜索的字符串进行分词,传入的前缀就是想要查找的前缀。默认状态下,前缀查询不做相关性分数计算,只是将所有的匹配的文档返回,然后赋予所有相关得分数值为1.
原理:需要遍历所有的倒排索引,并比较每个词项是否以搜索的前缀开头。
yml
# 匹配分词之后的词项。比如广州白云山,无法匹配到广州白云山公园。因为分此后的词项并没有广州白云山。
GET /index_naem/_search
{
"query": {
"prefix": {
"your_field": {
"value": "your_prifx"
}
}
}
}
# 匹配未分词的字段。比如广州白云山,可以匹配到广州白云山公园
GET /index_naem/_search
{
"query": {
"prefix": {
"your_field.keyword": {
"value": "your_prifx"
}
}
}
}
wildcard:通配符匹配(模糊搜索)
星号(*):表示0个或多个字符,用于匹配任意长度的字符串。
问号(?):表示一个字符,用于匹配任意单个字符。
yml
GET /index_naem/_search
{
"query": {
"wildcard": {
"your_field.keyword": {
"value": "*keywords*"
}
}
}
}
regexp:正则匹配查询
yml
GET /index_naem/_search
{
"query": {
"regexp": {
"your_field.keyword": {
"value": "正则表达式"
}
}
}
}
# 示例:搜索remark,Java后可以跟随任意数量的任意字符
GET /index_naem/_search
{
"query": {
"regexp": {
"remark": {
"value": "java.*"
}
}
}
}
fuzzy:支持编辑距离的模糊查询
能够在用户输入内容存在拼写错误或上下文不一致时,仍然返回与搜索词相似的文档。通过使用编辑距离算法来度量输入词与文档中词条的相似程度,模糊查询在保证搜索结果相关性的同时,有效提高了搜索容错能力。
编辑距离是指从一个单词转换到另一个单词需要编辑单字符串的次数。如中文集团到中东集团的编辑距离是1,只需要修改一个字符串。如果fuzziness值设置成2,会把编辑为2的华东集团也查询出来。
yml
GET /index_name/_search
{
"query": {
"fuzzy": {
"value": "search_text",
"fuzziness": "AUTO"
"prefix_length": 1
}
}
}
- fuzziness参数用于编辑举例的设置,其中默认值为AUTO,支持数值为0,1,2.如果设置越界则会提示错误。
- prefix_length:搜索词的前缀长度,在长度内不会应用模糊匹配。默认是0,即整个词都会被模糊匹配。
term set:用于解决多值字段中的文档匹配问题
yml
GET /index_name/_search
{
"query": {
"terms_set": {
"<filed_name>": {
"terms": ["<term1>","<term2>"],
"minimun_should_match_filed" : "<minimun_should_match_filed_name>",
# minimun_should_match_filed或者minimun_should_match_script
"minimun_should_match_script": {
"source": "<script>"
}
}
}
}
}
<field_name>:指定要查询的字段名,这个字段通常是一个多值字段。
terms:提供一组词项,用于在指定字段中进行匹配。
minimum_should_match_field:指定一个包含匹配数量的字段名,其值应用作要匹配的最少术语数,以便返回文档。
minimum_should_match_script:提供一个自定义脚本,用于动态计算匹配数量。如果需要动态设置匹配所需的术语数,这个参数将非常有用。
全文检索
全文检索查询旨在基于相关性搜索和匹配文本数据。这些查询会对输入的文本进行分析,将其拆分为词项(单个单词),并执行诸如分词、词干处理和标准化等操作。此类检索主要应用于非结构化文本数据,如文章和评论等。
match分词查询
对于match查询,其底层逻辑的概述:
1.分词:首先,输入的查询文本会被分词器进行分词。词器会将文本拆分成一个个词项(terms),如单词、短语或特定字符。
分词器通常根据特定的语言规则和配置进行操作。
2.匹配计算:一旦查询被分词,ES将根据査询的类型和参数计算文档与査询的匹配度。对于match查询,ES将比较查询的词项与倒排索引中的词项,并计算文档的相关性得分。相关性得分衡量了文档与查询的匹配程度。
3.结果返回:根据相关性得分,ES将返回最匹配的文档作为搜索结果。搜索结果通常按照相关性得分进行排序,以便最相关的文档排在前面。
yml
GET /index_name/_search
{
"query": {
"match": {
"field": "测试"
}
}
}
# 多字段匹配。比如搜索电池标准新国标,可以搜索出标签=新国标的和名称为电池标准的
GET /index_name/_search
{
"query": {
"multi_match": "电池标准新国标",
"field": ["name", "label"]
}
}
# and搜索 测试技术 and 指导说明 and 标准
GET /index_name/_search
{
"query": {
"match": {
"field": "测试技术指导说明标准",
"operator": "and"
}
}
}
# 最少匹配2个
GET /index_name/_search
{
"query": {
"match": {
"field": "测试技术指导说明标准",
"minimum_should_match": "2"
}
}
}
match_phrase短语查询
match phrase査询在Elasticsearch中用于执行短语搜索,它不仅匹配整个短语,而且还考虑了短语中各个词的顺序和位置。这种查询类型对于搜索精确短语非常有用,尤其是在用户输入的查询与文档中的文本表达方式需要严格匹配时。
yml
GET _analyze
{
"analyzer": "ik_smart",
"text": "广州白云山" # 分词结果:广州 白云山
}
GET _analyze
{
"analyzer": "ik_max_word",
"text": "广州白云山" # 分词结果:广州 白云山 白云 云山
}
如果上面的检索词为广州白云,通过ik_max_word分词,那么将无法搜索到广州白云山。则需要配置slop来指定最大间隔距离。
GET /index_name/_search
{
"query": {
"match_phrase": {
"<field_name>": {
"query": "<query_string>",
"slop": 2 # 间隔距离
}
}
}
}
query_string 支持与或非表达式查询
query_string查询是一种灵活的査询类型,它允许使用Lucene查询语法来构建复杂的搜索查询。这种查询类型支持多种逻辑运算符,包括与(AND)、或(OR)和非(NOT),以及通配符、模糊搜索和正则表达式等功能。query string查询可以在单个或多个字段上进行搜索,并且可以处理复杂的查询逻辑。
应用场景包括高级搜索、数据分析和报表等,适合处理需满足特定需求、要求支持与或非表达式的复杂查询任务,通常用于专业领域或需要高级查询功能的应用中。
- 基本语法
yml
GET /index_name/_search
{
"query": {
"query_string": {
"query":"<your_query_string>",
"default_field": "<filed_name>"
}
}
}
# 例子:
GET /index_name/_search
{
"query": {
"query_string": {
"query": "西湖 OR 雁荡山",
"default_field": "address"
}
}
}
GET /people/_search
{
"query": {
"query_string": {
"query": "小红 OR (李四 AND 雁荡山)",
"fields": ["name", "interest"]
}
}
}
simple_query_string 简化的query_string
yml
GET /index_name/_search
{
"query": {
"simple_query_string": {
"query": "广州公园",
"default_field": ["name","address"],
"default_operator": "and"
}
}
}
GET /index_name/_search
{
"query": {
"simple_query_string": {
"query": "广州 + 公园",
"default_field": ["name", "address"],
}
}
}
组合查询BoolQuery
布尔查询可以按照布尔逻辑条件组织多条查询语句,只有符合整个布尔条件的文档才会被搜索出来。
在布尔条件中,可以包含两种不同的上下文。
- 搜索上下文(query context): 使用搜索上下文时,Elasticsearch需要计算每个文档与搜索条件的相关度得分这个得分的计算需使用一套复杂的计算公式,
有一定的性能开销,带文本分析的全文检索的查询语句很适合放在搜索上下文中。 - 过滤上下文(filter context): 使用过滤上下文时,Elasticsearch只需要判断搜索条件跟文档数据是否匹配,例如使用Termquery判断一个值是否跟搜索内容一致,使用Range query判断某数据是否位于某个区间等。
过滤上下文的査询不需要进行相关度得分计算,还可以使用缓存加快响应速度,很多术语级查询语句都适合放在过滤上下文中。
布尔查询一共支持四种组合类型:
mast:可包含多个查询条件,每个条件均满足的文档才能被搜索到,每次查询需要计算相关度得分,属于搜索上下文should:可包含多个查询条件,不存在must和fter条件时,至少要满足多个查询条件中的一个,文档才能被搜索到,否则需满足的条件数量不受限制,匹配到的查询越多相关度越高,也属于搜索上下文filter:可包含多个过滤条件,每个条件均满足的文档才能被搜索到,每个过滤条件不计算相关度得分,结果在一定条件下会被缓存,属于过滤上下文mast_not:可包含多个过滤条件,每个条件均不满足的文档才能被搜索到,每个过滤条件不计算相关度得分,结果在一定条件下会被缓存,属于过滤上下文
HighLight高亮
highlight 关键字: 可以让符合条件的文档中的关键词高亮。highlight相关属性:
- pre_tags 前缀标签
- post_tags 后缀标签
- tags_schema 设置为styled可以使用内置高亮样式·
- require_field_match 多字段高亮需要设置为false
yml
#指定ik分词器
PUT /products
{
"settings" : {
"index" : {
"analysis.analyzer.default.type": "ik_max_word"
}
}
}
PUT /products/_doc/1
{
"proId" : "2",
"name" : "牛仔男外套",
"desc" : "牛仔外套男装春季衣服男春装夹克修身休闲男生潮牌工装潮流头号青年春秋棒球服男 7705浅蓝常规 XL",
"timestamp" : 1576313264451,
"createTime" : "2019-12-13 12:56:56"
}
PUT /products/_doc/2
{
"proId" : "6",
"name" : "HLA海澜之家牛仔裤男",
"desc" : "HLA海澜之家牛仔裤男2019时尚有型舒适HKNAD3E109A 牛仔蓝(A9)175/82A(32)",
"timestamp" : 1576314265571,
"createTime" : "2019-12-18 15:56:56"
}
#测试
GET /products/_search
{
"query": {
"term": {
"name": {
"value": "牛仔"
}
}
},
"highlight": {
"fields": {
"*": {}
}
}
}
# 自定义标签
GET /products/_search
{
"query": {
"term": {
"name": {
"value": "牛仔"
}
}
},
"highlight": {
"fields": {
"name":{
"pre_tags": "<a>",
"post_tags": "</a>"
}
}
}
}
地理空间位置查询
地理空间位置查询是数据库和搜索系统中的一个重要特性,特别是在地理信息系统(GIS)和位置服务中。它允许用户基于地理位置信息来搜索和过滤数据。在Elasticsearch这样的全文搜索引擎中,地理空间位置查询被广泛应用,例如在旅行、房地产、物流和零售等行业,用于提供基于位置的搜索功能。
在Elasticsearch中,地理空间数据通常存储在ge0_point字段类型中。这种字段类型可以存储纬度和经度坐标,用于表示地球上的一个点。以下是一个使用geo_distance查询的例子,它会找到距离特定点一定距离内的所有文档。
yml
# 地理空间位置查询
# 创建索引
PUT /tourist_spots
{
"mappings": {
"properties": {
"name": {
"type": "text",
"analyzer": "ik_max_word",
"search_analyzer": "ik_max_word"
},
"location": {
"type": "geo_point"
}
}
}
}
# 插入文档
POST /tourist_spots/_doc
{
"name": "故宫博物院",
"location": {
"lat": 39.9159,
"lon": 116.3945
},
"city": "北京"
}
POST /tourist_spots/_doc
{
"name": "西湖",
"location": {
"lat": 30.2614,
"lon": 120.1479
},
"city": "杭州"
}
POST /tourist_spots/_doc
{
"name": "雷峰塔",
"location": {
"lat": 30.2511,
"lon": 120.1347
},
"city": "杭州"
}
POST /tourist_spots/_doc
{
"name": "苏堤春晓",
"location": {
"lat": 30.2584,
"lon": 120.1383
},
"city": "杭州"
}
# 搜索包含故宫或博物院的景点:
GET /tourist_spots/_search
{
"query": {
"match": {
"name": "故宫 博物院"
}
}
}
# 查询北京附近的景点
GET /tourist_spots/_search
{
"query": {
"bool": {
"must": {
"match_all": {}
},
"filter": {
"geo_distance": {
"distance": "10km",
"distance_type": "arc",
"location": {
"lat": 39.9159,
"lon": 116.3945
}
}
}
}
}
}
# 查询杭州西湖5km附近的景点
#雷峰塔 - 位于西湖附近,距离约2.8公里。
#苏堤春晓 - 位于西湖边,距离西湖中心约1公里。
GET /tourist_spots/_search
{
"query": {
"bool": {
"must": {
"match_all": {}
},
"filter": {
"geo_distance": {
"distance": "5km",
"distance_type": "arc",
"location": {
"lat": 30.2614,
"lon": 120.1479
}
}
}
}
}
}
向量检索
Elasticsearch 8.x引入了一个重要的新特性:向量检索(Vector Search),特别是通过KNN(K-Nearest Neighbors)算法支持向量近邻检索。这一特性使得Elasticsearch在机器学习、数据分析和推荐系统等领域的应用变得更加广泛和强大。
向量检索的基本思路是,将文档(或数据项)表示为高维向量,并使用这些向量来执行相似性搜索。在Elasticsearch中,这些向量被存储在dense_vector类型的字段中,然后使用KNN算法来找到与给定向量最相似的其他向量。
yml
# 向量检索
PUT /products_vector
{
"mappings": {
"properties": {
"name": {
"type": "text"
},
"embedding": {
"type": "dense_vector",
"dims": 4 # 你的向量维度,示例是 4
}
}
}
}
PUT /products_vector/_doc/1
{
"name": "牛仔外套",
"embedding": [0.1, 0.2, 0.05, 0.3]
}
PUT /products_vector/_doc/2
{
"name": "海澜之家牛仔裤",
"embedding": [0.15, 0.18, 0.07, 0.25]
}
PUT /products_vector/_doc/3
{
"name": "篮球运动鞋",
"embedding": [0.9, 0.88, 0.85, 0.95]
}
PUT /products_vector/_doc/4
{
"name": "螺丝刀",
"embedding": [0.95, -0.8, 0.12, -0.9]
}
GET /products_vector/_search
{
"size": 3,
"query": {
"script_score": {
"query": {
"match_all": {}
},
"script": {
"source": "cosineSimilarity(params.query_vector, 'embedding') + 1.0",
"params": {
"query_vector": [0.12, 0.21, 0.05, 0.29]
}
}
}
}
}
实践:实现CSDN文章检索
yml
# 实现CSDN博客文章搜索
# 定义模型
PUT csdn_blogs
{
"settings": {
"number_of_shards": 1,
"number_of_replicas": 1
},
"mappings": {
"properties": {
"title": {
"type": "text",
"analyzer": "ik_max_word",
"search_analyzer": "ik_smart"
},
"content": {
"type": "text",
"analyzer": "ik_max_word",
"search_analyzer": "ik_smart"
},
"author": {
"type": "keyword"
},
"tags": {
"type": "keyword"
},
"date": {
"type": "date",
"format": "yyyy-MM-dd'T'HH:mm:ss"
}
}
}
}
# 插入数据
PUT csdn_blogs/_doc/1
{
"title": "Python编程入门",
"content": "Python是一种广泛使用的高级编程语言。",
"author": "张三",
"tags": ["Python", "编程"],
"date": "2023-08-01T12:00:00"
}
PUT csdn_blogs/_doc/2
{
"title": "Java开发技巧",
"content": "Java是一种流行的面向对象的编程语言。",
"author": "李四",
"tags": ["Java", "开发"],
"date": "2023-08-02T14:00:00"
}
PUT csdn_blogs/_doc/3
{
"title": "JavaScript基础教程",
"content": "本教程将引导你学习JavaScript的基本概念和语法。",
"author": "王五",
"tags": ["JavaScript", "教程", "编程"],
"date": "2023-08-03T10:00:00"
}
PUT csdn_blogs/_doc/4
{
"title": "深度学习在自然语言处理中的应用",
"content": "深度学习技术如何改变自然语言处理领域?",
"author": "赵六",
"tags": ["深度学习", "自然语言处理", "AI"],
"date": "2023-08-04T11:00:00"
}
PUT csdn_blogs/_doc/5
{
"title": "Docker容器化入门",
"content": "Docker是一个流行的容器化平台,用于构建和运行应用程序。",
"author": "钱七",
"tags": ["Docker", "容器化", "开发"],
"date": "2023-08-05T12:00:00"
}
PUT csdn_blogs/_doc/6
{
"title": "云原生架构设计",
"content": "如何设计适应云计算环境的现代应用架构。",
"author": "孙八",
"tags": ["云原生", "架构", "云计算"],
"date": "2023-08-06T13:00:00"
}
PUT csdn_blogs/_doc/7
{
"title": "区块链技术解析",
"content": "深入理解区块链技术的原理和应用。",
"author": "周九",
"tags": ["区块链", "技术", "解析"],
"date": "2023-08-07T14:00:00"
}
PUT csdn_blogs/_doc/8
{
"title": "大数据处理框架Hadoop",
"content": "Hadoop是一个开源的分布式计算框架。",
"author": "吴十",
"tags": ["大数据", "Hadoop", "分布式"],
"date": "2023-08-08T15:00:00"
}
PUT csdn_blogs/_doc/9
{
"title": "Python中的面向对象编程",
"content": "深入探讨Python中的面向对象编程概念,包括类、对象、继承和多态。",
"author": "陈十一",
"tags": ["Python", "编程", "面向对象"],
"date": "2023-08-12T10:00:00"
}
PUT csdn_blogs/_doc/10
{
"title": "使用Python进行数据科学",
"content": "介绍如何使用Python进行数据分析、数据可视化和机器学习。",
"author": "周十二",
"tags": ["Python", "数据科学", "编程"],
"date": "2023-08-15T11:00:00"
}
PUT csdn_blogs/_doc/11
{
"title": "Python Web开发框架Django入门",
"content": "Django是一个高级的Python Web框架,用于快速开发安全、维护性强的网站。",
"author": "吴十三",
"tags": ["Python", "Web开发", "Django", "编程"],
"date": "2023-08-18T12:00:00"
}
# 搜索包含"Python"的博客
GET csdn_blogs/_search
{
"query": {
"multi_match": {
"query": "Python",
"fields": ["title^2", "content", "tags"]
}
}
}
# 在这个查询中,multi_match 查询用于在多个字段(标题、内容和标签)中搜索关键词 "Python"。
# 标题字段的权重被设为2,意味着标题中包含关键词的文章将有更高的相关性得分。
# 搜索包含"Python"的文章,同时限定这些文章的发布日期,并要求文章必须包含"编程"标签
GET csdn_blogs/_search
{
"query": {
"bool": {
"must": [
{
"multi_match": {
"query": "Python",
"fields": ["title^2", "content"]
}
},
{
"range": {
"date": {
"gte": "2023-08-01T00:00:00",
"lte": "2023-08-31T23:59:59"
}
}
},
{
"term": {
"tags": "编程"
}
}
]
}
}
}