Elasticsearch Query DSL 整理总结(查询)

一、概念

es提供的以restful风格进行交互的DSL,请求体是JSON格式。
主要有两种类型:
第一种是叶子查询语句(Leaf Query),用于查询某个特定的字段,例如match,term,
第二种是复合查询语句,也就是组合了多个叶子查询或者嵌套了其它的复合查询的语句,例如bool组合查询、
fifter查询、range查询等等,是根据多个字段的查询组成。

二、Query and filter 的区别

query语句查询的时候,要计算匹配度(_score分数),fifter与会值关心是否匹配,不会计算得分。
GET /_search
{
  "query": {
    "bool": {
      "": [
        { "match": { "title":   "Search"        }},
        { "match": { "content": "Elasticsearch" }}
      ],
      "filter": [
        { "term":  { "status": "published" }},
        { "range": { "publish_date": { "gte": "2015-01-01" }}}
      ]
    }
  }
}

例子分析:

(1)、query参数在最外层,所以是处于整个query context中。
(2)、整个bool查询,都是query的子查询语句,所以里面的must、match会计算得分(匹配度)
(3)、bool子查询语句中的被filter包裹起来的部分,是处于fifter context中,不会计算得分。

三、查询语句

1、简单查询

	(1)、GET /lib/user/_search  : 查询lib索引下的user类型的全部数据

	(2)、GET /lib/_search :查询lib索引下的全部类型的数据
	
	(3)、GET /_search :查询全部索引下的数据

2、精确查找

 如果需要按照精确值进行查询,最好是使用过滤器fifter,因为不会计算评分,而且容易被缓存。
 结合term查询,也就是对查询条件不做分词处理,精确匹配,一般用于id/数值/日期/布尔类型的查询
 constant_score,以非评分模式来执行term查询,将term转化为过滤器查询

(1)、精确查找数值:

	GET /my_store/products/_search
	{
	    "query" : {
	        "constant_score" : {  
	            "filter" : {
	                "term" : { 
	                    "price" : 20
	                }
	            }
	        }
	    }
	}

(2)、精确查找文本:

由于可能之间插入的时候,文本就已经分词存储了,但是term查询的时候又是精确查找,可能就找不到对应的
分词,所以如果文本要精确查找,mapping映射就要手动设置该文本字段不分词
DELETE my_store   //先删除索引

PUT /my_store    //手动指定映射
{
    "mappings" : {
        "products" : {
            "properties" : {
                "productID" : {
                    "type" : "string",
                    "index" : "not_analyzed"    //不分词
                }
            }
        }
    }

}

(3)、多值精确匹配

通过terms指定多组值,可以指定返回的文档数量和字段
GET /my_store/products/_search
{
  "from":0,    //从第一文档开始
  "size":2,     //查询两个文档
  "_source":["address","age"],  //返回的字段
    "query":{
      "terms":{
        "price":[20,10,30]
      }
    }
}

3、模糊查询

通过match查询,和term查询相反,会对搜索词语进行分词

(1)、match匹配(普通分词匹配)

GET /my_store/products/_search
{
    "query" : {
                "match" : {
                    "productID" : "XHDK-A-1293-#fJ3"
            }
    }
}

(2)、match_all查询所有 (普通分词匹配,无匹配条件,查询所有)


GET /my_store/products/_search
{
  "query": {
    "match_all": {
  
    }
  }
}

(3)、match_phrase(分词短语匹配)

短语匹配,对query条件里面的短语看成是一个整体,进行匹配,文档里面包含这个词项列表,
并且词项之间的顺序都是一样,也没有其它字符的间隔,就可以返回。

也可以使用slop这个关键字指定相隔的步长,也就是词项之间可以隔开的间隙,这样匹配规则就宽松一些。
GET /lib/user/_search
{
  "query": {
    "match_phrase": {
      "address": "huibei,wuhan"
    }
  }
}

4、match 的细节和本质

(1)、match本质上是一种bool类型的查询,有一个默认隐藏的参数operator,
默认的值是OR,例如以下例子,本质上就是搜索满足hobbies字段匹配football  或者basketball的文档
operator还可以显式的设置为and
GET matchtest/people/_search
{
  "query": {
    "match": {
      "hobbies": {
        "query": "football basketball",
        "operator": "or"
      }
    }
  }
}
(2)、analyzer分词器

	如果查询的时候,没有指定查询时使用的分词器,就会默认使用字段在mapping(字段映射)时指定的分词器。
	如果字段在mapping时也没有指定,就会使用默认的搜索分词器。

(3)、lenient参数
	
		默认是false,表示查询 条件和字段数据类型不匹配并且无法自动转换,就会报错,
		如果设置为true,就会忽略掉错误。
GET matchtest/_search
{
  "query": {
    "match": {
      "age" : {
        "query": "xxx",
        "lenient": true
      }
    }
  }
}
(4)、fuzzniess 参数(模糊查询)
	
	模糊查询,这里的模糊是对于分词之后的词项来说的,例如查找名字kevent时,
	就会找出与之相似的keveni, keveyi等。
	通过模糊搜索可以查询出存在一定相似度的单词,
	通过设置编辑距离(相似值和搜索的值之间,通过几次编辑次数,可以变成相同),
	例如,单词 "god" 只需要插入一个 'o' 字符就可以变为 "good",因此它们之间的编辑距离为 1。
	
	fuzzniess 参数取值规则是,AUTO:[low],[high],默认是AUTO:3,6 :
	意思是根据词项的长度判断,
	长度为0到2(x<low),代表必须要精确匹配,因为词项太短也没有什么相似度
	长度为3到5(low<=x<high),最大编辑距离为1,也就是可以通过一次编辑(新增/删除/更改)字符,变成和搜索值一样的数据,会被搜索出来。
	长度大于5(x>high),最大编辑距离为2


 (5)、prefix_length 参数(精确前缀,后面的字符模糊匹配)
		
		表示词项的前面几位字符,不能用模糊匹配,由于大部分的拼写错误发生在词的结尾,而不是词的开始,
		使用 prefix_length 就可以完成优化。
GET matchtest/_search
{
  "query": {
    "match": {
      "hobbies": {
        "query": "foatball",
        "fuzziness": "AUTO",
        "prefix_length": 3
      }
    }
  }
}

(6)、zero terms Query(匹配停用词)

字段使用 stop 分析器,这个分析器会将 stop words 停用词(to be or not to be 之类的)在索引时全都去掉。
zero_terms_query 就是为了解决这个问题而生的。它的默认值是 none ,
就是搜不到停止词(对 stop 分析器字段而言),如果设置成 all ,它的效果就和 match_all 类似,就可以搜到了。
GET matchtest1/_search
{
  "query": {
    "match": {
      "message": {
        "query": "to be or not to be",
        "operator": "and",
        "zero_terms_query": "all"
      }
    }
  }
}

(7)、cutoff frequency(划分词频)

查询字符串的时候,词项会分为低词频(出现的次数少,便于匹配)和高词频(出现次数多,不便于匹配)。
所以在搜索的时候,尽可能的匹配低词频的词项。

在查询的时候配置cutoff_frequency 就是用于实现这个需求的,cutoff_frequency 设置成 0.01 就表示:
词项在文档超过1%就是高词频,其它词项就是低词频
低词频(频率少,重要)参与匹配和评分,高词频参与评分,不参与匹配,相当于高词频的词项会被看成是停用词。

cutoff_frequency 配置有两种形式

	指定为一个分数( 0.01 )表示出现频率
	指定为一个正整数( 5 )则表示出现次数

(8)、synonyms (同义词)

	实际上就是提前在mapping里面设置一个词项的同义词字典,后面查询的时候,也会匹配这个同义词字典。
PUT /matchtest4
{
    "settings": {
        "index" : {
            "analysis" : {
                "analyzer" : {
                    "synonym" : {
                        "tokenizer" : "whitespace",
                        "filter" : ["synonym"]
                    }
                },
                "filter" : {
                    "synonym" : {
                        "type" : "synonym",
                        "synonyms" : [
                            "USA, united states of America"
                        ]
                    }
                }
            }
        }
    }
}
PUT /matchtest4/_mapping/synonyms_test
{
  "properties": {
    "message": {
      "type": "text",
      "analyzer": "synonym"
    }
  }
}
PUT /matchtest4/synonyms_test/1
{
  "message": "united states of America people"
}
GET /matchtest4/_search
{
  "query": {
    "match": {
      "message": {
        "query": "USA"
      }
    }
  }
}

4、排序

通过sort进行结果排序
GET /lib/user/_search
{
  "_source":{   //设置原数据的结果字段包含(include)和排除那些(exclude)
    "exclude": ["address","name"],
    "include": ["age","date"]
  },
  "query": {
    "match_phrase": {		//短语匹配
      "address": "huibei,wuhan"
    }
  },
  "sort": [    //指定排序	
    {
      "age": {      //对字段age进行排序
        "order": "desc"
      },
      "address": {     //address排序
        "order": "asc"
      }
    }
  ]
}

5、range范围查询

gt: > 大于(greater than)
lt: < 小于(less than)
gte: >= 大于或等于(greater than or equal to)
lte: <= 小于或等于(less than or equal to)

一般适用于日期和数组字段,字符串也可以(采用字典排序和字母排序)

6、wildcard查询(通配符查询)

	使用通配符*和?进行查询
	*: 代表一个或者多个字符
	?:代表任意一个字符
GET team/user/_search
{
  "query": {
    "wildcard": {
      "name":"chen*"   
    }
  }
}


GET team/user/_search
{
  "query": {
    "wildcard": {
      "name":"chen?iabing"
    }
  }
}
7、fuzzy查询(模糊查询)

	和上面写的在match的query语句里面加上fuzzniess参数是一样的效果。
GET team/user/_search
{
  "query": {
    "fuzzy": {
      "name":"chejiabing"
    }
  }
}
8、高亮显示

	匹配出的文档,里面的匹配词项,用自定义的标签包裹起来。
GET team/user/_search
{
  "query": {
    "fuzzy": {
      "name":"chejiabing"
    }
  },
  "highlight": {
    "pre_tags": ["<span style='color:red'>"],   //指定包裹的标签前半部分,默认的是<em>
    "post_tags": ["</span>"],                    //指定后半部分
    "fields": {
      "name": {}                               //name字段高量
    }
  }
}

9、null值的查询

exists这个语句用来查询存在值的信息,和must结合就代表,
查询不为null的数据(exists保证查询数据存在,must代表and,所以结合起来就是数据一定存在)
和must_not结合查询代表查询为null的数据(exists保证查询数据存在,must_not代表非)
GET ea/user/_search
{
  "query": {
    "bool": {
      "must_not":{
        "exists":{
          "field":"password"
        }
      }
    }
  }
}


//查询password!=null的数据
GET ea/user/_search
{
  "query": {
    "bool": {
      "must":{
        "exists":{
          "field":"password"
        }
      }
    }
  }
}

10、filter查询

缓存,不返回相关性(不计算分数),速度比query快

简单的过滤查询,post_filter
GET /lib/user/_search
{
  "post_filter": {
    "term": {
      "age":22
    }
  }
}

bool过滤查询

must :所有的语句都 必须(must) 匹配,与 AND 等价。
must_not :所有的语句都 不能(must not) 匹配,与 NOT 等价。
should:至少有一个语句要匹配,与 OR 等价。

must中的内容查询是并列的,相当于sql中的and/or,条件都满足才可以。
GET /lib/user/_search
{
  "query": {
    "bool": {
      "must": [
        {"term": {"age":22}},
        {"match":{"address": "湖北"}}
      ]
    }
  }
}


GET /lib/user/_search
{
  "post_filter": {
    "bool": {
       "should": [
        {"term":{"name":"郑元梅"}},
        {"term":{"age":33}}
      ],
      "must_not": [
        {"term":{"age":22}}
      ]
     
    }
  }
}
bool过滤查询\嵌套bool过滤查询\范围过滤\非空的过滤查询\简单的filter查询,都属于filter过滤查询。

11、聚合查询

sql中有许多的聚合函数,在es中页存在这些聚合函数,比如sum,avg,count等等
GET /lib/user/_search
{
  "size": 0,     //在使用聚合的时候,默认还会返回全部的文档结果,如果不需要,可以使用size限制
  "aggs": {
    "sum_age": {           //sum_age  指定返回字段的名称
      "sum": {            //sum是指定的聚合函数的名称
        "field": "age"    //这里指定聚合的字段
      }
    }
  }
}


GET /lib/user/_search
{
  "size": 0,
  "aggs": {
    "avg_age": {        //avg_age 指定返回字段的名称
      "avg": {			//avg是指定的聚合函数名称
        "field": "age"	//指定是聚合字段
      }
    }
  }
}

select *,avg(age) from user group by date;

GET /lib/user/_search
{
  "query": {
    "term": {
      "age": "22"
    }
  }, 
  "aggs": {
    "age_group": {
      "terms": {
        "field": "date"
      },
      "aggs": {      //直接在分组的聚合中,再次使用聚合求age的均值
        "age_avg": {
          "avg": {
            "field": "age"
          }
        }
      }
    }
  }
}


11、Multi Match Query

multi_match 查询建立在 match 查询之上,是对多个字段查询。
fields 字段中的值支持通配符* , 设置 mess* 依旧可以查询出 message 字段中的匹配。
GET multimatchtest/multimatch_test/_search
{
  "query": {
    "multi_match": {
      "query": "multimatch",
      "fields": ["subject", "mess*"]
    }
  }

在查询字段后使用 ^ 符号可以提高字段的权重,增加字段的分数 _score 。
GET multimatchtest/multimatch_test/_search
{
  "query": {
    "multi_match": {
      "query": "multimatch",
      "fields": ["subject^3", "mess*"]
    }
  }
}

multi_match 的查询类型:

<1>、best_fields (默认类型):
	 
	 返回与所有查询条件匹配的文档,但是只返回的文档评分是最佳匹配的字段的评分。
	 例如下面的例子,在 subject 和 message 两个字段上都查询 chinese food,
	 由于文档2里面的message字段匹配度最高,所以文档2会之间返回这个最高的评分
PUT multimatchtest/multimatch_test/1
{
  "subject": "food is delicious!",
  "message": "cook food"
}
PUT multimatchtest/multimatch_test/2
{
  "subject": "blabla blala",
  "message": "I like chinese food"
}

GET multimatchtest/multimatch_test/_search
{
  "query": {
    "multi_match": {
      "query": "chinese food",
      "fields": ["subject", "message"]
    }
  }
}


  "hits": {
    "total": 2,
    "max_score": 0.5753642,
    "hits": [
      {
        "_index": "multimatchtest",
        "_type": "multimatch_test",
        "_id": "2",
        "_score": 0.5753642,
        "_source": {
          "subject": "blabla blala",
          "message": "I like chinese food"
        }
      },
      {
        "_index": "multimatchtest",
        "_type": "multimatch_test",
        "_id": "1",
        "_score": 0.2876821,
        "_source": {
          "subject": "food is delicious!",
          "message": "cook food"
        }
      }
    ]
  }
}

	tie_breaker的作用是为了综合考虑其它字段的评分对结果的影响,因为如果是best_fields类型的查询,文档只会返回最佳
	匹配字段的得分,没有加上其它字段的得分。
	所以设置tie_breaker的作用是:在最佳评分的基础上,加上其它字段得分乘以tie_breaker。
	
	 

	<2>、most_fields (合并得分类型):
		
				将所有匹配到的字段得分总合合并起来。
GET multimatchtest/multimatch_test/_search
{
  "query": {
    "multi_match": {
      "query": "multimatch",
      "fields": ["subject", "message"],
      "type": "most_fields"
    }
  }
}
   <3>、phrase 和 phrase_prefix(短语匹配+dis_max)

	和best_fieIds类似,区别就在于
	phrase 使用 match_phrase & dis_max 实现
	phrase_prefix 使用 match_phrase_prefix & dis_max 实现

	也就是短语匹配+best_fieIds模式(直返回最佳匹配字段的分数)

12、cross_fields

	 most_fields 和 best_fields 类型都是词中心式(field-centric),也就是以分词项为搜索中心,如果文档里面没有保护完整的
	 分词项(如果是phrase/phrase_prefix ,会以短语为分词项),就匹配不到文档。
	 例如要查询 "blabla like" 字符串,并且指定 operator 为 and ,则会在同一个字段内搜索整个字符串,
	 只有一个字段内都有这两个词,才匹配上。
GET multimatchtest/_search
{
  "query": {
    "multi_match": {
      "query": "blabla like",
      "operator": "and",
      "fields": [ "subject", "message"],
      "type": "best_fields"
    }
  }
}
而 cross_fields 类型则是字段中心式的,例如,要查询 "blabla like" 字符串,查询字段为 "subject" 和 "message"。
会首先根据查询字符串生成一个词列表,然后以所有字段为中心,去匹配这个词列表里面的每个词项,
如果能匹配上,文档也就能够返回。
GET multimatchtest/_search
{
  "query": {
    "multi_match": {
      "query": "blabla like",
      "operator": "and",
      "fields": [ "subject", "message"],
      "type": "cross_fields"
    }
  }
}

cross_fields 的评分机制

也是由tie_breaker 来控制评分,tie_breaker 取值:
	0:获取最佳字段的分数为最终分数,默认值
	1: 将多个字段的分数合并
	0 < n < 1: 最佳字段评分与其它字段结合评分

版权声明:本文为qq_39188150原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。