一、概念
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版权协议,转载请附上原文出处链接和本声明。