1 DSL介绍
Elasticsearch提供了基于JSON的完整查询DSL(Domain Specific Language)来定义查询。
将查询DSL视为查询的AST(抽象语法树),它由两种子句组成:
-
叶子查询子句(Leaf query clauses)
在特定字段中查找特定值, 例如match,term或range查询 -
复合查询子句(Compound query clauses)
以逻辑方式组合多个叶子、复合查询为一个查询(例如bool或dis_max查询),
查询和过滤的区别
查询:用于检查内容与条件是否匹配,并且计算_score
元字段表示匹配度。查询的结构中以query参数来开始执行内容的查询。
过滤:不计算匹配得分,只是简单的决定文档是否匹配。过滤往往会被elasticsearch自动缓存起来提高性能。
查询的子句中也可以传递filter参数。
2 数据准备
- 准备一个商品的索引
PUT goods
{
"mappings": {
"properties": {
"id":{
"type": "long"
},
"name":{
"type": "text",
"analyzer": "ik_max_word"
},
"category":{
"type": "keyword"
},
"price":{
"type": "float"
},
"content":{
"type": "text",
"analyzer": "ik_max_word"
},
"create_at":{
"type": "date",
"format": ["yyyy-MM-dd hh:mm:ss"]
}
}
}
}
- 插入数据
PUT goods/_doc/1
{
"id":1,
"name": "苹果手机12",
"category":"手机",
"price":8999.00,
"content":"Apple iPhone 12 Pro Max (A2412) 256GB 海蓝色 支持移动联通电信5G 双卡双待手机",
"create_at":"2020-12-12 12:00:00"
}
PUT goods/_doc/2
{
"id":2,
"name": "华为手机P40",
"category":"手机",
"price":7999.00,
"content":"华为p40 5G手机 亮黑色 8+128G全网通",
"create_at":"2020-12-11 12:00:00"
}
3 文本查询
基本语法
GET /索引库名/_search
{
"query":{
"查询类型":{
"查询条件":"查询条件值"
}
}
}
- 查询类型:
- 例如:
match_all
,match
,term
,range
等等
- 例如:
- 查询条件:查询条件会根据类型的不同,写法也有差异,后面详细讲解
3.1 match 查询
3.1.1 查询所有(match_all)
GET goods/_search
{
"query": {"match_all": {}}
}
{
"took" : 1,
"timed_out" : false,
"_shards" : {
"total" : 1,
"successful" : 1,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : {
"value" : 2,
"relation" : "eq"
},
"max_score" : 1.0,
"hits" : [
{
"_index" : "goods",
"_type" : "_doc",
"_id" : "1",
"_score" : 1.0,
"_source" : {
"id" : 1,
"name" : "苹果手机12",
"category" : "手机",
"price" : 8999.0,
"content" : "Apple iPhone 12 Pro Max (A2412) 256GB 海蓝色 支持移动联通电信5G 双卡双待手机",
"create_at" : "2020-12-12 12:00:00"
}
},
{
"_index" : "goods",
"_type" : "_doc",
"_id" : "2",
"_score" : 1.0,
"_source" : {
"id" : 2,
"name" : "华为手机P40",
"category" : "手机",
"price" : 7999.0,
"content" : "华为p40 5G手机 亮黑色 8+128G全网通",
"create_at" : "2020-12-11 12:00:00"
}
}
]
}
}
可以不指定索引库:查询所有的索引库
GET _search
{
"query": {"match_all": {}}
}
3.1.2 match_none
这是match_all查询的逆函数,该查询不匹配任何文档
3.1.3 match query(匹配查询)
用于执行全文查询的标准查询,包括模糊匹配和短语或接近查询。
match类型查询,会把查询条件进行分词,然后进行查询,多个词条之间是or的关系(默认)
or
GET goods/_search?
{
"query": {
"match": {
"content": {
"query": "华为手机",
"operator": "or" # 默认就是or
}
}
}
}
查询结果: 两条记录都查出来了
{
"took" : 2,
"timed_out" : false,
"_shards" : {
"total" : 1,
"successful" : 1,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : {
"value" : 2,
"relation" : "eq"
},
"max_score" : 0.96994376,
"hits" : [
{
"_index" : "goods",
"_type" : "_doc",
"_id" : "2",
"_score" : 0.96994376,
"_source" : {
"id" : 2,
"name" : "华为手机P40",
"category" : "手机",
"price" : 7999.0,
"content" : "华为p40 5G手机 亮黑色 8+128G全网通",
"create_at" : "2020-12-11 12:00:00"
}
},
{
"_index" : "goods",
"_type" : "_doc",
"_id" : "1",
"_score" : 0.16613919,
"_source" : {
"id" : 1,
"name" : "苹果手机12",
"category" : "手机",
"price" : 8999.0,
"content" : "Apple iPhone 12 Pro Max (A2412) 256GB 海蓝色 支持移动联通电信5G 双卡双待手机",
"create_at" : "2020-12-12 12:00:00"
}
}
]
}
}
- 华为手机,经过分词分为:华为,手机
- 搜索的时候,content字段中包含手机,或者华为这两个词就可以被匹配出来
and
GET goods/_search?
{
"query": {
"match": {
"content": {
"query": "华为手机",
"operator": "and"
}
}
}
}
根据上面,这里应该只会查出华为手机
{
"took" : 8,
"timed_out" : false,
"_shards" : {
"total" : 1,
"successful" : 1,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : {
"value" : 1,
"relation" : "eq"
},
"max_score" : 0.96994376,
"hits" : [
{
"_index" : "goods",
"_type" : "_doc",
"_id" : "2",
"_score" : 0.96994376,
"_source" : {
"id" : 2,
"name" : "华为手机P40",
"category" : "手机",
"price" : 7999.0,
"content" : "华为p40 5G手机 亮黑色 8+128G全网通",
"create_at" : "2020-12-11 12:00:00"
}
}
]
}
}
minimum_should_match 最小匹配参数
在 or 与 and 间二选一有点过于非黑即白。 如果用户给定的条件分词后有 5 个查询词项,想查找只包含其中 4 个词的文档,该如何处理?将 operator 操作符参数设置成 and 只会将此文档排除,如果是or就会导致搜出的结果和用户的期望值差距较大。所以就引入了minimum_should_match
最小匹配数的参数:
这让我们可以指定必须匹配的词项数用来表示一个文档是否相关。我们可以将其设置为某个具体数字,更常用的做法是将其设置为一个百分数,因为我们无法控制用户搜索时输入的单词数量:
比如:下面这个查询我们指定了最小匹配数为2,所以只会查出华为手机
GET goods/_search?
{
"query": {
"match": {
"content": {
"query": "华为手机",
"operator": "or",
"minimum_should_match": 2
}
}
}
}
可以使用通配符: *
GET goods/_search
{
"query": {
"match": {
"name": {
"query": "p*",
"operator": "and"
}
}
}
}
{
"took" : 148,
"timed_out" : false,
"_shards" : {
"total" : 1,
"successful" : 1,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : {
"value" : 1,
"relation" : "eq"
},
"max_score" : 0.27779984,
"hits" : [
{
"_index" : "goods",
"_type" : "_doc",
"_id" : "2",
"_score" : 0.27779984,
"_source" : {
"id" : 2,
"name" : "华为手机P40",
"category" : "手机",
"price" : 7999.0,
"content" : "华为p40 5G手机 亮黑色 8+128G全网通",
"create_at" : "2020-12-11 12:00:00"
}
}
]
}
}
其他参数
- lenient: 可以设置为true来忽略数据类型匹配出错造成的异常,
不常用
- analyzer: 指定搜索时候使用的分词
eg: 使用标准分词器搜索华为手机
GET goods/_search?
{
"query": {
"match": {
"content": {
"query": "华为手机",
"operator": "or",
"analyzer": "standard",
"minimum_should_match": 2
}
}
}
}
eg: price 是 float 类型的,如果查询 price=2499x ,就会导致无法转换而报错: search_phase_execution_exception
GET goods/_search?
{
"query": {
"match": {
"price": {
"query": "8999xx"
}
}
}
}
就可以指定lenient为true来忽略这个错误
GET goods/_search?
{
"query": {
"match": {
"price": {
"query": "8999xx",
"lenient": "true"
}
}
}
}
3.2 Match Phrase Query(短语查询)
match_phrase 查询针对的是一个语句,比如 “like football”, 分析时也会将整个语句作为整体
词条位置
当一个字符串被分析时,分析器不仅只返回一个词条列表,它同时也返回原始字符串的每个词条的位置、或者顺序信息:
POST _analyze
{
"analyzer": "ik_max_word",
"text": "华为手机"
}
{
"tokens" : [
{
"token" : "华为",
"start_offset" : 0, # 偏移量
"end_offset" : 2, # 偏移量
"type" : "CN_WORD",
"position" : 0 # 位置
},
{
"token" : "手机",
"start_offset" : 2, # 偏移量
"end_offset" : 4, # 偏移量
"type" : "CN_WORD",
"position" : 1 # 位置
}
]
}
像match_phrase这样位置感知(Position-aware)的查询能够使用位置信息来匹配那些含有正确单词出现顺序的文档,且在这些单词之间没有插入别的单词
对于查询华为手机,必须满足:
- 字段中必须含有这两个分词
- 手机的位置必须比华为的位置大于1
演示
请求:查询content字段中时候有移动联通电信
GET goods/_search
{
"query": {
"match_phrase": {
"content": {
"query": "移动联通电信",
"analyzer": "ik_max_word"
}
}
}
}
响应:会查出苹果手机这一条
{
"took" : 1,
"timed_out" : false,
"_shards" : {
"total" : 1,
"successful" : 1,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : {
"value" : 1,
"relation" : "eq"
},
"max_score" : 2.526501,
"hits" : [
{
"_index" : "goods",
"_type" : "_doc",
"_id" : "1",
"_score" : 2.526501,
"_source" : {
"id" : 1,
"name" : "苹果手机12",
"category" : "手机",
"price" : 8999.0,
"content" : "Apple iPhone 12 Pro Max (A2412) 256GB 海蓝色 支持移动联通电信5G 双卡双待手机",
"create_at" : "2020-12-12 12:00:00"
}
}
]
}
}
如果查询的是移动电信联通
呢,根据前面说的必须要保证联通在电信前面,是不会查出数据的
GET goods/_search
{
"query": {
"match_phrase": {
"content": {
"query": "移动电信联通",
"analyzer": "ik_max_word"
}
}
}
}
{
"took" : 0,
"timed_out" : false,
"_shards" : {
"total" : 1,
"successful" : 1,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : {
"value" : 0,
"relation" : "eq"
},
"max_score" : null,
"hits" : [ ]
}
}
默认使用 match_phrase 时会精确匹配查询的短语,需要全部单词和顺序要完全一样,标点符号除外。,所以改了顺序之后就不到了
slop 参数
默认是0
slop 参数告诉 match_phrase 查询词条相隔多远时仍然能将文档视为匹配
什么是相隔多远? 意思是说为了让查询和文档匹配你需要移动词条多少次?
比如刚刚的移动电信联通
没有搜索出来,就可以通过这个slop去调整,能够搜索出来
GET goods/_search
{
"query": {
"match_phrase": {
"content": {
"query": "移动电信联通",
"analyzer": "ik_max_word",
"slop": 3
}
}
}
}
{
"took" : 3,
"timed_out" : false,
"_shards" : {
"total" : 1,
"successful" : 1,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : {
"value" : 1,
"relation" : "eq"
},
"max_score" : 0.6871974,
"hits" : [
{
"_index" : "goods",
"_type" : "_doc",
"_id" : "1",
"_score" : 0.6871974,
"_source" : {
"id" : 1,
"name" : "苹果手机12",
"category" : "手机",
"price" : 8999.0,
"content" : "Apple iPhone 12 Pro Max (A2412) 256GB 海蓝色 支持移动联通电信5G 双卡双待手机",
"create_at" : "2020-12-12 12:00:00"
}
}
]
}
}
3.3 match_phrase_prefix
原理跟match_phrase类似,唯一的区别,就是把最后一个term作为前缀去搜索。
比如输入 hello w 进行搜索
- hello就是去进行match,搜索对应的doc
- w,会作为前缀,去扫描整个倒排索引,找到所有w开头的doc
- 然后找到所有doc中,即包含hello,又包含w开头的字符的doc
- 根据你的slop去计算,看在slop范围内,能不能让hello w,正好跟doc中的hello和w开头的单词的position相匹配
- max_expansions:指定prefix最多匹配多少个term,超过这个数量就不继续匹配了,限定性能
默认情况下,前缀要扫描所有的倒排索引中的term,去查找w打头的单词,但是这样性能太差。可以用max_expansions限定,w前缀最多匹配多少个term,就不再继续搜索倒排索引了。
- 尽量不要用,因为,最后一个前缀始终要去扫描大量的索引,性能可能会很差
- max_expansions:指定prefix最多匹配多少个term,超过这个数量就不继续匹配了
可以通过这个去做那种联想搜索。
3.4 multi_match(多字段查询)
multi_match查询以match查询为基础,以允许多字段查询:
基本使用
GET 索引库/_search
{
"query": {
"multi_match": {
"query": "查询关键词",
"fields": ["字段1","字段2"],
"operator": "and" # 默认是or 查询关键词分词之后,是or还是and
}
}
}
查询关键词:手机12
GET goods/_search
{
"query": {
"multi_match": {
"query": "手机12",
"fields": ["content","name"],
"operator": "and"
}
}
}
只会查询苹果手机12:因为是and连接,手机12会被分词为苹果和手机
{
"took" : 5,
"timed_out" : false,
"_shards" : {
"total" : 1,
"successful" : 1,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : {
"value" : 1,
"relation" : "eq"
},
"max_score" : 0.9752057,
"hits" : [
{
"_index" : "goods",
"_type" : "_doc",
"_id" : "1",
"_score" : 0.9752057,
"_source" : {
"id" : 1,
"name" : "苹果手机12",
"category" : "手机",
"price" : 8999.0,
"content" : "Apple iPhone 12 Pro Max (A2412) 256GB 海蓝色 支持移动联通电信5G 双卡双待手机",
"create_at" : "2020-12-12 12:00:00"
}
}
]
}
}
如果改成or:
GET goods/_search
{
"query": {
"multi_match": {
"query": "手机12",
"fields": ["content","name"]
}
}
}
{
"took" : 2,
"timed_out" : false,
"_shards" : {
"total" : 1,
"successful" : 1,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : {
"value" : 2,
"relation" : "eq"
},
"max_score" : 0.9752057,
"hits" : [
{
"_index" : "goods",
"_type" : "_doc",
"_id" : "1",
"_score" : 0.9752057,
"_source" : {
"id" : 1,
"name" : "苹果手机12",
"category" : "手机",
"price" : 8999.0,
"content" : "Apple iPhone 12 Pro Max (A2412) 256GB 海蓝色 支持移动联通电信5G 双卡双待手机",
"create_at" : "2020-12-12 12:00:00"
}
},
{
"_index" : "goods",
"_type" : "_doc",
"_id" : "2",
"_score" : 0.20199655,
"_source" : {
"id" : 2,
"name" : "华为手机P40",
"category" : "手机",
"price" : 7999.0,
"content" : "华为p40 5G手机 亮黑色 8+128G全网通",
"create_at" : "2020-12-11 12:00:00"
}
}
]
}
}
加权:可以使用(^)表示法增强各个字段:
GET /_search
{
"query": {
"multi_match" : {
"query" : "华为手机",
"fields" : [ "content^3", "name" ]
}
}
}
content字段是name字段重要三倍
如果未提供任何字段,则multi_match查询默认为index.query.default_field索引设置,而默认设置为。 提取映射中所有符合词条查询条件的字段,并过滤元数据字段。 然后将所有提取的字段组合起来以构建查询。
查询类型(TODO)
多匹配查询内部执行方式取决于:type参数,他的取值有:
- best_fields(默认):查找匹配任何字段的文档,但是使用最佳匹配的
_score
。 - most_fields:查找匹配任何字段的文档,结合每个字段的
_score
。 - cross_fields: 用相同的分词器处理字段,把这些字段当做一个大字段。查找任何字段的每个单词
- phrase:每个字段上进行短语匹配查询(match_phrase),结合每个字段的
_score
。 - phrase_prefix:每个字段上进行短语前缀匹配查询(match_phrase_prefix),结合每个字段的
_score
。
- best_fields: 在同一个字段中,搜索多个单词的时候,此参数最有用,比如一个字段包含
华为手机
,比包含手机
或者包含华为
更有意义,best_fields会对每个字段生成一个匹配查询,并且封装成dis_max
查询,来找到最佳匹配字段,例如:
GET goods/_search
{
"query": {
"multi_match": {
"query": "华为手机",
"fields": ["name","content"],
"type": "best_fields"
}
}
}
回执行为:
GET goods/_search
{
"query": {
"dis_max": {
"queries": [
{
"match": {
"content": "华为手机"
}
},
{
"match": {
"name": "华为手机"
}
}
]
}
}
}
4 字段查询
前面的查询都会先分析查询字符串(进行分词),而字段查询只针对存储在反向索引中的精确索引词。查询关键字不会先进行分词
这些精确值可能是数字、时间、布尔或者那些未分词的字符串
4.1 单字段查询
查询指定字段中包含的指定内容进行查找。
eg: 查询name字段包含苹果手机的
GET goods/_search
{
"query": {
"term": {
"name": "苹果手机"
}
}
}
- 苹果手机不会被分词,作为一个整体去匹配,name字段中是否包含的苹果手机
这里的查询结果是空!!!!
{
"took" : 0,
"timed_out" : false,
"_shards" : {
"total" : 1,
"successful" : 1,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : {
"value" : 0,
"relation" : "eq"
},
"max_score" : null,
"hits" : [ ]
}
}
name为苹果手机12
的那条文档,在倒序索引中,会被ik分词器分词为苹果
,手机
,12
,显然这三个索引词都和我们指定的苹果手机不匹配。说到底就是我们的查询关键字不会先进行分词
4.2 多词条精确匹配(terms)
terms` 查询和 term 查询一样,但它允许你指定多值进行匹配。
GET goods/_search
{
"query": {
"terms": {
"name": [
"手机",
"苹果"
]
}
}
}
4.3 范围查询 (range)
根据指定字段包含的值(日期,数字或字符串等)范围查找文档
入门
查询价格大等于8000的商品
GET goods/_search
{
"query": {
"range": {
"price": {
"gte": 8000
}
}
}
}
接受的参数
- gte:大于等于
- gt:大于
- lte:小于等于
- lt:小于
- boots:设置查询的加权值,默认是1.0
日期匹配
入门
GET goods/_search
{
"query": {
"range": {
"create_at": {
"gte": "now-d/d" # 当前时间的上一天, 四舍五入到最近的一天
"lt": "now-1d/d" # 当前时间, 四舍五入到最近的一天
}
}
}
}
时间的数学表达
Elasticsearch中时间可以表示为now, 也就是系统当前时间, 也可以是以||
结尾的日期字符串表示.
在日期之后, 可以选择一个或多个数学表达式:
表示式 | 含义 |
---|---|
y | 年 |
M | 月 |
w | 周 |
d | 天 |
H | 时 |
m | 分 |
s | 秒 |
eg:
-
+1h —— 加1小时;
-
-1d —— 减1天;
-
/d —— 四舍五入到最近的一天.
-
/M —— 四舍五入到最近的一天.
说明: 假设系统当前时间now = 2018-10-01 12:00:00 : -
now+1h
: now的毫秒值 + 1小时, 结果是: 2018-10-01 13:00:00. -
now-1h
: now的毫秒值 - 1小时, 结果是: 2018-10-01 11:00:00. -
now-1h/d
: now的毫秒值 - 1小时, 然后四舍五入到最近的一天的起始, 结果是: 2018-10-01 00:00:00. -
2018.10.01||+1M/d
: 2018-10-01的毫秒值 + 1月, 再四舍五入到最近一天的起始, 结果是: 2018-11-01 00:00:00
关于时间的四舍五入
向上舍入: 移动到舍入范围的最后一毫秒;
向下舍入: 一定到舍入范围的第一毫秒.
- “gt”: “2018-12-18||/M” —— 大于日期, 需要向上舍入, 结果是2018-12-31T23:59:59.999, 也就是不包含整个12月.
- “gte”: “2018-12-18||/M” —— 大于或等于日期, 需要向下舍入, 结果是 2018-12-01, 也就是包含整个12月.
- “lt”: “2018-12-18||/M” —— 小于日期, 需要向上舍入, 结果是2018-12-01, 也就是不包含整个12月.
- “lte”: “2018-12-18||/M” —— 小于或等于日期, 需要向下舍入, 结果是2018-12-31T23:59:59.999, 也就是包含整个12月.
日期格式化
GET goods/_search
{
"query": {
"range": {
"create_at": {
"lt": "2021-01-01",
"format": "yyyy-MM-dd"
}
}
}
}
指定时区
GET goods/_search
{
"query": {
"range": {
"create_at": {
"time_zone": "+01:00",
"gte": "2020-01-01 00:00:00",
"format": "yyyy-MM-dd hh:mm:ss"
}
}
}
}
5 其他查询
5.1 是否存在查询
查询指定字段包含任何非空值的文档
查询name字段不为空的商品
GET goods/_search
{
"query": {
"exists": {
"field": "name"
}
}
}
name为空的情况:
- null
- [] (空数组)
- [null]
- 没有name字段的文档
查询指定字段包含为空值的文档
上一个的逆操作
GET goods/_search
{
"query": {
"bool": {
"must_not": [
{
"exists": {
"field": "name"
}
}
]
}
}
}
5.2 前缀查询(prefix)
查询字段包含指定前缀的索引词(不分词)。
插叙name字段前缀为华为的商品
GET goods/_search
{
"query": {
"prefix": {
"name": {
"value": "华为"
}
}
}
}
5.3 通配符查询(wildcard)
注意的是这个查询会比较慢,需要在多个索引词上面重复执行。为了避免极端缓慢的查询,应该避免查询的时使用通配符开头
-
*:匹配任意字符(包含空字符)
-
?:匹配任意单个字符
GET goods/_search
{
"query": {
"wildcard": {
"name": "华为?"
}
}
}
5.4 模糊查询(Fuzziness)
fuzzniess 参数可以使查询的字段具有模糊搜索的特性。来先了解下什么是模糊搜索。
什么是模糊搜索?
模糊搜索是指系统允许被搜索信息和搜索提问之间存在一定的差异,这种差异就是“模糊”在搜索中的含义。例如,查找名字Smith时,就会找出与之相似的Smithe, Smythe, Smyth, Smitt等。(百度百科)
通过模糊搜索可以查询出存在一定相似度的单词,那么怎么计算两个单词是否有相似度以及相似度的大小呢?这就要了解下另外一个概念:Levenshtein Edit Distance
Levenshtein Edit Distance 叫做莱文斯坦距离,是编辑距离的一种。指两个字串之间,由一个转成另一个所需的最少编辑操作次数。允许的编辑操作包括将一个字符替换成另一个字符,插入一个字符,删除一个字符。
例如,单词 “god” 只需要插入一个 ‘o’ 字符就可以变为 “good”,因此它们之间的编辑距离为 1。
入门
- 查询ipone
GET goods/_search
{
"query": {
"match": {
"content": {
"query": "ipone"
}
}
}
}
没有查到结果
{
"took" : 1,
"timed_out" : false,
"_shards" : {
"total" : 1,
"successful" : 1,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : {
"value" : 0,
"relation" : "eq"
},
"max_score" : null,
"hits" : [ ]
}
}
- 执行下面的查询,便可模糊查出结果
GET goods/_search
{
"query": {
"match": {
"content": {
"query": "ipone",
"fuzziness": 1
}
}
}
}
{
"took" : 39,
"timed_out" : false,
"_shards" : {
"total" : 1,
"successful" : 1,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : {
"value" : 1,
"relation" : "eq"
},
"max_score" : 0.5053002,
"hits" : [
{
"_index" : "goods",
"_type" : "_doc",
"_id" : "1",
"_score" : 0.5053002,
"_source" : {
"id" : 1,
"name" : "苹果手机12",
"category" : "手机",
"price" : 8999.0,
"content" : "Apple iPhone 12 Pro Max (A2412) 256GB 海蓝色 支持移动联通电信5G 双卡双待手机",
"create_at" : "2020-12-12 12:00:00"
}
}
]
}
}
或者
GET goods/_search
{
"query": {
"fuzzy": {
"content": {
"value": "ipone",
"fuzziness": 1
}
}
}
}
{
"took" : 5,
"timed_out" : false,
"_shards" : {
"total" : 1,
"successful" : 1,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : {
"value" : 1,
"relation" : "eq"
},
"max_score" : 0.5053002,
"hits" : [
{
"_index" : "goods",
"_type" : "_doc",
"_id" : "1",
"_score" : 0.5053002,
"_source" : {
"id" : 1,
"name" : "苹果手机12",
"category" : "手机",
"price" : 8999.0,
"content" : "Apple iPhone 12 Pro Max (A2412) 256GB 海蓝色 支持移动联通电信5G 双卡双待手机",
"create_at" : "2020-12-12 12:00:00"
}
}
]
}
}
fuzziness 参数取值规则
在查询 text 或者 keyword 类型的字段时, fuzziness 可以看做是莱文斯坦距离。
fuzziness 参数的取值如下
- 0,1,2: 表示最大可允许的莱文斯坦距离
- auto:
会根据词项的长度来产生可编辑距离,它还有两个可选参数,形式为AUTO:[low],[high], 分别表示短距离参数和长距离参数;如果没有指定,默认值是 AUTO:3,6 表示的意义如下- 0…2 单词长度为 0 到 2 之间时必须要精确匹配,这其实很好理解,单词长度太短是没有相似度可言的,例如 ‘a’ 和 ‘b’。
- 3…5: 单词长度 3 到 5 个字母时,最大编辑距离为 1
-
5: 单词长度大于 5 个字母时,最大编辑距离为 2
如果不设置 fuziness 参数,查询是精确匹配的。
fuzziness 在绝大多数场合都应该设置成 AUTO(来自官网)
对在中文环境下Fuzziness这个模糊查询的没有什么意义,
prefix_length 参数
prefix_length 表示不能没模糊化的初始字符数。由于大部分的拼写错误发生在词的结尾,而不是词的开始,使用 prefix_length 就可以完成优化。注意 prefix_length 必须结合 fuzziness 参数使用。默认0
prefix_length设置3,前三个字母就不能模糊化,所以这里ihpone不会匹配到数据
GET goods/_search
{
"query": {
"fuzzy": {
"content": {
"value": "ihpone",
"fuzziness": 1,
"prefix_length": 3
}
}
}
}
或者
GET goods/_search
{
"query": {
"match": {
"content": {
"query": "ihpone",
"fuzziness": 1,
"prefix_length": 3
}
}
}
}
max_expansions参数
模糊查询将要扩展的索引词最大数量,默认50
ID查询
GET goods/_search
{
"query": {
"ids": {
"type": "_doc",
"values": [1,2]
}
}
}
在老版本,es还没有取消的type的时候,请求是上面这样的,后来取消type了 (Deprecation: [types removal] Types are deprecated in [ids] queries.)
GET goods/_search
{
"query": {
"ids": {
"values": [1,2]
}
}
}