ElasticSearch 查询DSL(Domain Specific Language,领域特定语言),基于6.8.15版本
语法笔记。
- Query Context(查询上下文): 除了判断文档是否匹配外,查询子句还会计算
_score
元数据字段中的相关性分数。每个查询子句要表达的含义是“此文档与此查询子句匹配程度如何?” - Filter Context(过滤器上下文):过滤上下文主要用于过滤结构化数据,Elasticsearch 会自动缓存常用的过滤器,以提高性能。每个查询子句表达的含义是“此文档是否与此查询子句匹配?”
Compounded Queries(混合查询)
Boolean Query
通过must
、should
、must_not
和 filter
组织查询条件,形成一种或与非逻辑查询。允许逻辑嵌套。
- must:必须满足的条件,相当于 and
- should:满足其中一个条件即可,相当于 or
- must not:必须不满足条件,相当于 not ,不会参与评分
- filter:与 must 含义相同,不参与评分
举例:
// type 是低版本的概念,后续已经被作废。6.8可以填_doc 或者 不填写
POST /users{/_doc}/_search
{
"query": {
"bool" : {
//注意这里的不同
//_name 字段给每个查询条件起一个名字
//这样在查询记录里就会多一个 matched_queries 来指明命中了那些条件
"must" : {
"term" : {
"user.id" : {"query":"kimchy" ,"_name":"fist"}
}
},
"filter": {"term" : { "tags" : "production" } },
"must_not" : {"range" : {"age" : { "gte" : 10, "lte" : 20 }}},
"should" : [
{ "term" : { "tags" : "env1" } },
{ "term" : { "tags" : "deployed" } }
],
//表示,should中n个条件,必须满足其中n个,默认为1
"minimum_should_match" : 1,
// 最终得分 = 分数 * boost
"boost" : 1.0
}
}
}
Boosting Query
POST /articles/_search
通过 positive
和 negative
两种搜索条件的匹配,来正面(positive
)或负面(negative
)影响 _score
的计算。
POST /articles/_search
{
"query": {
"boosting": {
//必须要满足的条件
"positive": {
"match": {
"title": "Java"
}
},
//扣分条件,满足条件则最终分数 = positive 匹配得分 * negative_boost
"negative": {
"match": {
"title": "developer"
}
},
"negative_boost": 0.1
}
}
}
Constant Score Query
因为filter
查询,并不会计算分数,因此这种方式可以为其查询结果给出一个固定分数。
POST /articles/_search
{
"query": {
"constant_score": {
//这里必须是filter
"filter": {
"term": {
"title.keyword": "Java developer"
}
},
// filter 最终的得分为 1.2
"boost": 1.2
}
}
}
Dis Max Query (DisjunctionMaxQuery)
通过多个查询条件匹配文档,以匹配条件中最高分数作为最终得分,其他非高分匹配的条件,需要通过tie_breaker
来影响得分。
POST /articles/_search
{
"query": {
"dis_max": {
//标识非最高分匹配命中,分数需要 乘以 0.7
"tie_breaker": 0.7,
//用于指定 Constant Score Query 这种的固定分数,constant_query 里面指定的优先
"boost": 1.2,
//有多个匹配条件,假设第一匹配分数最高
//最终得分 = 第一个匹配得分 + 第二个匹配得分 * 0.7
"queries": [
{"match": {"title": "Java developer"}},
{"match": {"content": "Java"}},
{"constant_score": {
"filter": {
"term": {
"title.keyword": "Java developer"
}
},
//这个比外面的boost优先级高
"boost": 3
}}
]
}
}
}
Function Score Query
通过一些函数来计算最终的得分情况。
final_score = boost_mode(query_score,score_mode(fun_score_1...2))
- score_mode:multiply、sum、avg、first、max、min
- boost_mode:multiply、replace(特殊,只使用func_score,不用query_socre)、sum、avg、max、min
- function:weight(不指定就是它)、field_value_factor(基于指定字段)、script_score(通过函数脚本)、衰减函数 (linear、exp、guass) 和 random_score(0到1浮点随机数)
下面这个例子基于:
function: weight、field_value_factor
score_mode: sum
boost_mode: sum
POST /articles/_search
{
"query": {
"function_score": {
"boost":2,
//这里使用 match_all 不会打分去 boost = 2,所以 query_score = 2
"query": {"match_all": {}},
"functions": [
//符合次filter匹配的 fun_score_1 = size(假设10) * weight = 20
{
"filter": {
"term": {
"title.keyword": "Java developer"
}
},
"weight": 2,
"field_value_factor": {
"field": "size"
}
},
//符次filter条件的 fun_score_2 = weight = 2
{
"filter": {
"match":{
"content":"Spring"
}
},
"weight": 2
},
//符次filter条件的 fun_score_3 = weight = 1
{
"filter": {
"match":{
"content":"NIO"
}
},
"weight": 1
}
],
//functions 中多个计分方式,他们之间是通过累加的方式
//即 fun_score = sum(fun_score_1,fun_score_2,fun_score_3) = 23
"score_mode": "sum",
//最终得分 = sum(query_score,fun_score)
"boost_mode": "sum",
// 指定 functions 的最终打分不能超过 30 Math.min(fun_score,30)
"max_boost": 30
}
}
}
// script_score 使用,替代上面的 fun_score_1 中 field_value_factor 即可
"script_score": {
"script": {
"params": {
"a": 5,
"b": 1.2
},
"source": "params.a / Math.pow(params.b, doc['my-int'].value)"
}
}
Full Text Queries(全文本搜索)
match
将查询文本分词后,在指定字段上进行匹配。
莱文斯坦距离:指两个字符串之间,由一个转成另一个所需的最少编辑操作次数。
- 将一个字符替换成另一个字符
- 插入一个字符
- 删除一个字符
POST /articles/_search
{
"query": {
"match": {
"content": {
//这个文本会被,下面的 analyzer
"query": "ja1a spr0ng",
"analyzer": "standard",
//表示分词成term之后,查询是通过and连接的,默认是or
"operator": "and",
//表示是否忽略类型转换错误
//比如说通过 size 字段(数值类型)查询传了一个 字符串默认 false 会报错的
"lenient": "true",
//标识是否启用模糊查询,使用 Levenshtein Edit Distance 莱文斯坦距离做模糊匹配
//默认是0,标识精确匹配
//AUTO表示 0-2 必须精确 3-5 支持最小编辑为1 5 以上最小编辑为 2
"fuzziness": "AUTO",
//模糊查询时,term 的前 2 个必须一样,从第三个字符开始允许编辑
"prefix_length": 2,
//表示是否过滤掉停用次,默认是none,如果期望不过滤使用 all
"zero_terms_query": "none",
//定义高频词,分数表示,term 出现频率 正数表示出现次数
//在 operator 为 and match 会被改写成 bool 查询逻辑,低频次是一个must的逻辑,高频词是should的逻辑,高频词会影响到最终的得分
"cutoff_frequency": 2
}
}
}
}
match_phrase
相比于match
,match_phrase
外强调了term
的位置,也就是要求匹配文本具有一定的语法顺序。可以用来做用户输入补全。
POST /articles/_search
{
"query": {
"match_phrase": {
"content": {
//Unity3d 和 DDL 这两个词必须存在,并且顺序先后出现
"query": "Unity3d DDL",
//表示 Unity3d 和 DDL 中间只能差一个词
"slop": 1
}
}
}
}
match_phrase_prefix
与 match_phrase
一样的,但最后一个词可以只给前缀
{
"query": {
"match_phrase_prefix": {
"content": {
"query": "Spring Fr",
//这个参数???
"max_expansions": 0
}
}
}
}
multi_match
文档多字段匹配
POST /articles/_search
{
"query": {
"multi_match": {
"query": "spring",
//content^3^3 表示content字段匹配打分会 乘以 3
//titl* 表示模糊匹配字段,如果匹配不到会报错
"fields": ["content^3","titl*"]
}
}
}
common
common存在是为了提高,低频次的匹配精度,降低停用词的影响但不排除停用词。
在实际匹配过程中,如果停用词参与了匹配那么,那么结果会出现很多无关文档,如果省略掉则会造成失语现象,如“no happy” no被去掉后可能就变成“haapy”。这时候就可以用common
POST /articles/_search
{
"query": {
"common": {
"content": {
//实际会被解析成BooleanQuery
"query": "no Spring Framework",
"cutoff_frequency": 0.001,
//再and的情况下
//非停用词是must逻辑
//停用词是 should 逻辑
"low_freq_operator": "and"
}
}
},
"profile": "true"
}
Term-level queries
term
针对term进行查询,如果是 exact_value(keyword)他不会被分词,term就是文本本身,如果是 full_text 文本会被分词器分成n多个term,只要其中有任何一个term在 查询条件内就会返回。
POST /articles/_search
{
"query": {
"term": {
"content": {
//这里的值一定是分词后的term值,区分大小写
//虽然full_text 里面可能是Spring,分词后是spring ,那就应该用spring查询
"value": "spring",
//最终打分结果会乘以 boost
"boost": 0
}
}
}
}
Terms Query
只要字段中包括其中一个term就会返回,也允许讲其他文档的字段值作为查询条件。
POST /articles/_search
{
"query": {"terms": {"content": ["spring","cloud"]}}
}
GET /tweets/_search
{
"query" : {
"terms" : {
"user" : {
//使用 index=users type=_doc id=2 path=followers(字段)的值作为terms query查询
"index" : "users",
"type" : "_doc",
"id" : "2",
"path" : "followers"
}
}
}
}
Terms Set Query
与terms query 一样,但是可以额外制定必须匹配数量,这个数量可以来源于文档的字段,或者通过脚本计算。
POST /users/_search
{
"query": {
"terms_set":{
"followers":{
"terms":[1,30],
// 这个表示匹配的数量必须是字段num的value
# "minimum_should_match_field":"num",
// 这里指明匹配的数量必须是 terms 数组的长度
"minimum_should_match_script": {
// Math.min(params.num_terms, doc['required_matches'].value)
"source": "params.num_terms"
}
}
}
}
}
Range Query
范围查询 gt(大于)gte(大于等于)lt(小于)lte(小于等于)
POST /users/_search
{
"query": {
"range": {
"num": {
"gte": 1,
"lte": 20
}
}
}
}
POST /users/_search
{
"query": {
"range": {
"birthday": {
//日期字段可以使用now-1d/d 表示大于当前时间减一天的数据
//这部分函数可以查看 Date Math 相关文档
"gt": "now-1d/d"
}
}
}
}
Exists Query
查询字段不为null 或 [] 的文档,如果想表达 not exists 就必须用 bool query 包装
POST /users/_search
{
"query": {
"exists": {
"field": "followers"
}
}
}
POST /users/_search
{
"query": {
"bool": {
"must_not": [
{"exists": {"field": "followers"}}
]
}
}
}
Prefix Query
文本不分词,进行前缀查询
GET /_search
{ "query": {
"prefix" : { "user" : "ki" }
}
}
Wildcard Query
term 模糊匹配,* 0个或者多个字符 ? 表示 任何一个字符
POST /users/_search
{
"query": {
"wildcard": {
"username.keyword": {
"value": "111 ? 222"
}
}
}
}
Regexp Query
正则表达式匹配,运行速度取决于正则表达式 .* 都非常慢,应该尽可能使用长前缀匹配。
- . 表示任意一个字符
-
- 表示前一个字符出现1次或者多次
-
- 表示前一个字符出现0次或者多次
- ? 表示出现0次或者一次
- {1,4} 表示出现 大于等于1次 小于等于 4次 {4}表示出现4次,{2,}表示出现2次以上
- (ab)+ 表示(ab)一组出现 1次或者多次
- | 表示 一个or 的逻辑 如 aa|bb aa or bb
- [abc] 表示 abc [a-c] 表示 abc [^abc] 表示 非 abc \ 用来表示转义 可以转移 -
- ab~cd 表示 以a 开头紧接着是b 然后跟个非c的任何字符,以f结尾
- <1-100> 表示一个时间范围,可以匹配到80
- & 表示前后两个正则都需要满足,aaa.+&.+bbb aaabbb match
- @ 表示跟任何 string 都匹配
POST /users/_search
{
"query": {
"regexp": {
"username.keyword": "111.*"
}
}
}
Fuzzy Query
最大编辑举例匹配(莱文斯坦距离)
POST /users/_search
{
"query": {
"fuzzy": {
"username.keyword": {
"value": "111 2 2",
//表示最大可以编辑两次
"fuzziness": 2,
//前面6个字符必须一样
"prefix_length": 6,
//???
"max_expansions": 100
}
}
}
}
Type Query
index 下 类型查找,之后类型被弱化了,所以没什么用了
POST /users/_search
{
"query": {
"type":{
"value":"_doc"
}
}
}
Ids Query
查询制定id的文档
GET /users/_search
{
"query": {
"ids" : {
"type" : "_doc",
"values" : ["1", "4", "100"]
}
}
}
操作的时候不制定前面的索引,直接使用/_search
将会搜索所有的索引