elasticsearch查询语法

一、精确查询
当进行精确值查找时, 我们会使用过滤器(filters)
1.term 精确值查找

{
    "term" : {
        "price" : 20
    }
}

2.bool 布尔过滤器

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

3.terms 查找多个精确值

{
    "terms" : {
        "price" : [20, 30]
    }
}

4.range 查找处于某个范围内的文档

"range" : {
    "price" : {
        "gte" : 20,
        "lte" : 40
    }
 }

gt: > 大于(greater than)
lt: < 小于(less than)
gte: >= 大于或等于(greater than or equal to)
lte: <= 小于或等于(less than or equal to)
5.exists 返回那些在指定字段有任何值的文档

{
	"exists" : { "field" : "tags" }
 }

6.missing 它返回某个特定 无 值字段的文档

{
 	"missing" : { "field" : "tags" }
 }

二、匹配查询
1.match 主要的应用场景就是进行全文搜索

{
    "query": {
        "match": {
            "title": "QUICK!"
        }
    }
}

Elasticsearch 执行上面这个 match 查询的步骤是:
1)检查字段类型 。

标题 title 字段是一个 string 类型( analyzed )已分析的全文字段,这意味着查询字符串本身也应该被分析。
2)分析查询字符串 。

将查询的字符串 QUICK! 传入标准分析器中,输出的结果是单个项 quick 。因为只有一个单词项,所以 match 查询执行的是单个底层 term 查询。
3)查找匹配文档 。

用 term 查询在倒排索引中查找 quick 然后获取一组包含该项的文档。
4)为每个文档评分 。

用 term 查询计算每个文档相关度评分 _score ,这是种将词频(term frequency,即词 quick 在相关文档的 title 字段中出现的频率)和反向文档频率(inverse document frequency,即词 quick 在所有文档的 title 字段中出现的频率),以及字段的长度(即字段越短相关度越高)相结合的计算方式。

operator match 查询还可以接受 operator 操作符作为输入参数,默认情况下该操作符是 or 。我们可以将它修改成 and 让所有指定词项都必须匹配

{
    "query": {
        "match": {
            "title": {      
                "query":    "BROWN DOG!",
                "operator": "and"
            }
        }
    }
}

minimum_should_match 最小匹配参数

{
  "query": {
    "match": {
      "title": {
        "query": "quick brown dog",
        "minimum_should_match": "75%"
      }
    }
  }
}

boost 控制任何查询语句的相对的权重, boost 的默认值为 1 ,大于 1 会提升一个语句的相对权重

{
    "query": {
        "bool": {
            "must": {
                "match": {  
                    "content": {
                        "query":    "full text search",
                        "operator": "and"
                    }
                }
            },
            "should": [
                { "match": {
                    "content": {
                        "query": "Elasticsearch",
                        "boost": 3 
                    }
                }},
                { "match": {
                    "content": {
                        "query": "Lucene",
                        "boost": 2 
                    }
                }}
            ]
        }
    }
}

2.dis_max 不使用 bool 查询,可以使用 dis_max 即分离 最大化查询(Disjunction Max Query) 。分离(Disjunction)的意思是 或(or) ,这与可以把结合(conjunction)理解成 与(and) 相对应。分离最大化查询(Disjunction Max Query)指的是: 将任何与任一查询匹配的文档作为结果返回,但只将最佳匹配的评分作为查询的评分结果返回

{
    "query": {
        "dis_max": {
            "queries": [
                { "match": { "title": "Brown fox" }},
                { "match": { "body":  "Brown fox" }}
            ]
        }
    }
}

查出评分最高的两条相关数据

tie_breaker 将其他匹配语句的评分也考虑其中

{
    "query": {
        "dis_max": {
            "queries": [
                { "match": { "title": "Quick pets" }},
                { "match": { "body":  "Quick pets" }}
            ],
            "tie_breaker": 0.3
        }
    }
}

3.multi_match 查询为能在多个字段上反复执行相同查询提供了一种便捷方式。
multi_match 多匹配查询的类型有多种,其中的三种恰巧与 了解我们的数据 中介绍的三个场景对应,即:
1)best_fields 最佳字段(默认值,可以不指定;这表示它会为每个字段生成一个 match 查询,然后将它们组合到 dis_max 查询的内部)、

{
  "dis_max": {
    "queries":  [
      {
        "match": {
          "title": {
            "query": "Quick brown fox",
            "minimum_should_match": "30%"
          }
        }
      },
      {
        "match": {
          "body": {
            "query": "Quick brown fox",
            "minimum_should_match": "30%"
          }
        }
      },
    ],
    "tie_breaker": 0.3
  }
}

上面这个查询用 multi_match 重写成更简洁的形式:

{
    "multi_match": {
        "query":                "Quick brown fox",
        "type":                 "best_fields", 
        "fields":               [ "title", "body" ],
        "tie_breaker":          0.3,
        "minimum_should_match": "30%" 
    }
}

字段名称可以用模糊匹配的方式给出:

{
    "multi_match": {
        "query":  "Quick brown fox",
        "fields": "*_title"	//字段名称包含title的
    }
}

可以使用 ^ 字符语法为单个字段提升权重,在字段名称的末尾添加 ^boost ,其中 boost 是一个浮点数

{
    "multi_match": {
        "query":  "Quick brown fox",
        "fields": [ "*_title", "chapter_title^2" ] 
    }
}

2)most_fields 多数字段、

{
  "query": {
    "bool": {
      "should": [
        { "match": { "street":    "Poland Street W1V" }},
        { "match": { "city":      "Poland Street W1V" }},
        { "match": { "country":   "Poland Street W1V" }},
        { "match": { "postcode":  "Poland Street W1V" }}
      ]
    }
  }
}

为每个字段重复查询字符串会使查询瞬间变得冗长,可以采用 multi_match 查询,将 type 设置成 most_fields 然后告诉 Elasticsearch 合并所有匹配字段的评分:

{
  "query": {
    "multi_match": {
      "query":       "Poland Street W1V",
      "type":        "most_fields",
      "fields":      [ "street", "city", "country", "postcode" ]
    }
  }
}

用 most_fields 这种方式搜索也存在某些问题,这些问题并不会马上显现:
它是为多数字段匹配 任意 词设计的,而不是在 所有字段 中找到最匹配的。
它不能使用 operator 或 minimum_should_match 参数来降低次相关结果造成的长尾效应。
词频对于每个字段是不一样的,而且它们之间的相互影响会导致不好的排序结果。

3)cross_fields 跨字段查询。
cross_fields 使用词中心式(term-centric)的查询方式,它将所有字段当成一个大字段,并在 每个字段 中查找 每个词。

{
    "query": {
        "multi_match": {
            "query":       "peter smith",
            "type":        "cross_fields", 
            "operator":    "and",
            "fields":      [ "first_name", "last_name" ]
        }
    }
}

cross_fields 类型首先分析查询字符串并生成一个词列表,然后它从所有字段中依次搜索每个词。这种不同的搜索方式很自然的解决了 字段中心式 查询三个问题中的二个。剩下的问题是逆向文档频率不同。

copy_to 复制

{
    "mappings": {
        "person": {
            "properties": {
                "first_name": {
                    "type":     "string",
                    "copy_to":  "full_name" 
                },
                "last_name": {
                    "type":     "string",
                    "copy_to":  "full_name" 
                },
                "full_name": {
                    "type":     "string"
                }
            }
        }
    }
}

first_name 和 last_name 字段中的值会被复制到 full_name 字段。

三、短句匹配
match_phrase
match_phrase 查询首先将查询字符串解析成一个词项列表,然后对这些词项进行搜索,但只保留那些包含 全部 搜索词项,且 位置 与搜索词项相同的文档。

{
    "query": {
        "match_phrase": {
            "title": "quick brown fox"
        }
    }
}

match_phrase 查询首先将查询字符串解析成一个词项列表,然后对这些词项进行搜索,但只保留那些包含 全部 搜索词项,且 位置 与搜索词项相同的文档。 比如对于 quick fox 的短语搜索可能不会匹配到任何文档,因为没有文档包含的 quick 词之后紧跟着 fox 。

slop 参数告诉 match_phrase 查询词条相隔多远时仍然能将文档视为匹配 。 相隔多远的意思是为了让查询和文档匹配你需要移动词条多少次?

{
    "query": {
        "match_phrase": {
            "title": {
            	"query": "quick fox",
            	"slop":  1
            }
        }
    }
}

尽管在使用了 slop 短语匹配中所有的单词都需要出现, 但是这些单词也不必为了匹配而按相同的序列排列。 有了足够大的 slop 值, 单词就能按照任意顺序排列了。
slop比较耗性能

position_increment_gap 告诉 Elasticsearch 应该为数组中每个新元素增加当前词条 position 的指定值。

{
    "properties": {
        "names": {
            "type": "string",
            "position_increment_gap": 100
        }
    }
}

所以现在当我们再索引 names 数组时,会产生如下的结果:
Position 1: john
Position 2: abraham
Position 103: lincoln
Position 104: smith

四、部分匹配
1.prefix 前缀查询

{
    "query": {
        "prefix": {
            "postcode": "W1"
        }
    }
}

2.wildcard 通配符与正则表达式查询

{
    "query": {
        "wildcard": {
            "postcode": "W?F*HW" 
        }
    }
}

这个查询会匹配包含 W1F 7HW 和 W2F 8HW 的文档
? 匹配 1 和 2 , * 与空格及 7 和 8 匹配。

3.regexp 正则式查询允许写出这样更复杂的模式:

{
    "query": {
        "regexp": {
            "postcode": "W[0-9].+" 
        }
    }
}

这个正则表达式要求词必须以 W 开头,紧跟 0 至 9 之间的任何一个数字,然后接一或多个其他字符。

4.match_phrase_prefix 查询时输入即搜索

{
    "match_phrase_prefix" : {
        "brand" : "johnnie walker bl"
    }
}

这种查询的行为与 match_phrase 查询一致,不同的是它将查询字符串的最后一个词作为前缀使用,换句话说,可以将之前的例子看成如下这样:
johnnie
跟着 walker
跟着以 bl 开始的词
如果通过 validate-query API 运行这个查询查询,explanation 的解释结果为:

“johnnie walker bl*”

max_expansions 限制前缀扩展的影响,一个合理的值是可能是 50

{
    "match_phrase_prefix" : {
        "brand" : {
            "query":          "johnnie walker bl",
            "max_expansions": 50
        }
    }
}

参数 max_expansions 控制着可以与前缀匹配的词的数量,它会先查找第一个与前缀 bl 匹配的词,然后依次查找搜集与之匹配的词(按字母顺序),直到没有更多可匹配的词或当数量超过 max_expansions 时结束。

Ngrams

{
    "filter": {
        "autocomplete_filter": {
            "type":     "edge_ngram",
            "min_gram": 1,
            "max_gram": 20
        }
    }
} 

这个配置的意思是:对于这个 token 过滤器接收的任意词项,过滤器会为之生成一个最小固定值为 1 ,最大为 20 的 n-gram 。

keyword 分词器是一个非操作型分词器,这个分词器不做任何事情,它接收的任何字符串都会被原样发出,因此它可以用来处理 not_analyzed 的字段值,但这也需要其他的一些分析转换,如将字母转换成小写。

五、相关度评分

当匹配到一组文档后,需要根据相关度排序这些文档,不是所有的文档都包含所有词,有些词比其他的词更重要。一个文档的相关度评分部分取决于每个查询词在文档中的 权重 。

词频
词在文档中出现的频度是多少?频度越高,权重 越高 。 5 次提到同一词的字段比只提到 1 次的更相关。

{
  "mappings": {
    "doc": {
      "properties": {
        "text": {
          "type":          "string",
          "index_options": "docs" 
        }
      }
    }
  }
}

将参数 index_options 设置为 docs 可以禁用词频统计及词频位置,这个映射的字段不会计算词的出现次数,对于短语或近似查询也不可用。要求精确查询的 not_analyzed 字符串字段会默认使用该设置。

逆向文档频率
词在集合所有文档里出现的频率是多少?频次越高,权重 越低 。常用词如 and 或 the 对相关度贡献很少,因为它们在多数文档中都会出现,一些不常见词如 elastic 或 hippopotamus 可以帮助我们快速缩小范围找到感兴趣的文档。

字段长度归一值( norm )
字段的长度是多少?字段越短,字段的权重 越高 。如果词出现在类似标题 title 这样的字段,要比它出现在内容 body 这样的字段中的相关度更高。

{
  "mappings": {
    "doc": {
      "properties": {
        "text": {
          "type": "string",
          "norms": { "enabled": false } 
        }
      }
    }
  }
}

这个字段不会将字段长度归一值考虑在内,长字段和短字段会以相同长度计算评分。

标准分词器
whitespace (空白字符)分词器按空白字符 —— 空格、tabs、换行符等等进行简单拆分

standard 分词器使用 Unicode 文本分割算法 来寻找单词 之间 的界限,并且输出所有界限之间的内容。
GET /_analyze?tokenizer=standard
You’re my ‘favorite’.
在这个例子中,You’re 中的撇号被视为单词的一部分,然而 ‘favorite’ 中的单引号则不会被视为单词的一部分, 所以分词结果如下: You’re 、 my 、 favorite 。

uax_url_email 分词器和 standard 分词器工作方式极其相同。 区别只在于它能识别 email 地址和 URLs 并输出为单个语汇单元。 standard 分词器则不一样,会将 email 地址和 URLs 拆分成独立的单词。 例如,email 地址 joe-bloggs@foo-bar.com 的分词结果为 joe 、 bloggs 、 foo 、 bar.com 。

ICU 插件
ICU 插件是处理英语之外语言的必需工具,非常推荐你安装并使用它,不幸的是,因为是基于额外的 ICU 函数库, 不同版本的ICU插件可能并不兼容之前的版本,当更新插件的时候,你需要重新索引你的数据。
icu_分词器
可以把文本分成独立的单词( ??? , ?? , ?? , ??? , ??? ),这使得文档更容易被搜索到。

GET /_analyze?tokenizer=standard
向日葵

GET /_analyze?tokenizer=icu_tokenizer
向日葵
标准分词器 在前面的例子中将每个字符输出为单独的词汇单元: 向 , 日 , 葵 。 icu_分词器 会输出单个词汇单元 向日葵 (sunflower) 。

标准分词器 和 icu_分词器 的另一个不同的地方是后者会将不同书写方式的字符(例如,βeta )拆分成独立的词汇单元 — β 和 eta— ,而前者则会输出单个词汇单元: βeta 。

六、聚合

桶:满足特定条件的文档的集合
指标:简单的数学运算(例如最小值、平均值、最大值,还有汇总)

GET /cars/transactions/_search
{
    "size" : 0,
    "aggs" : { 
        "popular_colors" : { 
            "terms" : { 
              "field" : "color"
            }
        }
    }
}

聚合操作被置于顶层参数 aggs 之下(如果你愿意,完整形式 aggregations 同样有效)。

然后,可以为聚合指定一个我们想要名称,本例中是: popular_colors 。

最后,定义单个桶的类型 terms 。

嵌套桶

GET /cars/transactions/_search
{
   "size" : 0,
   "aggs": {
      "colors": {
         "terms": {
            "field": "color"
         },
         "aggs": {
            "avg_price": { 
               "avg": {
                  "field": "price"
               }
            },
            "make": { 
                "terms": {
                    "field": "make" 
                }
            }
         }
      }
   }
}

注意前例中的 avg_price 度量仍然保持原位。
另一个聚合 make 被加入到了 color 颜色桶中。
这个聚合是 terms 桶,它会为每个汽车制造商生成唯一的桶。

让我们看看返回的响应(为了简单我们只显示部分结果):

{
...
   "aggregations": {
      "colors": {
         "buckets": [
            {
               "key": "red",
               "doc_count": 4,
               "make": { 
                  "buckets": [
                     {
                        "key": "honda", 
                        "doc_count": 3
                     },
                     {
                        "key": "bmw",
                        "doc_count": 1
                     }
                  ]
               },
               "avg_price": {
                  "value": 32500 
               }
            },

...
}

正如期望的那样,新的聚合嵌入在每个颜色桶中。
现在我们看见按不同制造商分解的每种颜色下车辆信息。
最终,我们看到前例中的 avg_price 度量仍然维持不变。

GET /cars/transactions/_search
{
   "size" : 0,
   "aggs": {
      "colors": {
         "terms": {
            "field": "color"
         },
         "aggs": {
            "avg_price": { "avg": { "field": "price" }
            },
            "make" : {
                "terms" : {
                    "field" : "make"
                },
                "aggs" : { 
                    "min_price" : { "min": { "field": "price"} }, 
                    "max_price" : { "max": { "field": "price"} } 
                }
            }
         }
      }
   }
}

我们需要增加另外一个嵌套的 aggs 层级。
然后包括 min 最小度量。
以及 max 最大度量。

得到以下输出(只显示部分结果):

{
...
   "aggregations": {
      "colors": {
         "buckets": [
            {
               "key": "red",
               "doc_count": 4,
               "make": {
                  "buckets": [
                     {
                        "key": "honda",
                        "doc_count": 3,
                        "min_price": {
                           "value": 10000 
                        },
                        "max_price": {
                           "value": 20000 
                        }
                     },
                     {
                        "key": "bmw",
                        "doc_count": 1,
                        "min_price": {
                           "value": 80000
                        },
                        "max_price": {
                           "value": 80000
                        }
                     }
                  ]
               },
               "avg_price": {
                  "value": 32500
               }
            },
...

有了这两个桶,我们可以对查询的结果进行扩展并得到以下信息:

有四辆红色车。
红色车的平均售价是 $32,500 美元。
其中三辆红色车是 Honda 本田制造,一辆是 BMW 宝马制造。
最便宜的红色本田售价为 $10,000 美元。
最贵的红色本田售价为 $20,000 美元。

histogram 条形图

GET /cars/transactions/_search
{
   "size" : 0,
   "aggs":{
      "price":{
         "histogram":{ 
            "field": "price",
            "interval": 20000
         },
         "aggs":{
            "revenue": {
               "sum": { 
                 "field" : "price"
               }
             }
         }
      }
   }
}	

histogram 桶要求两个参数:一个数值字段以及一个定义桶大小间隔。
sum 度量嵌套在每个售价区间内,用来显示每个区间内的总收入。

date_histogram 按时间统计(日期格式字段)
GET /cars/transactions/_search
{
“size” : 0,
“aggs”: {
“sales”: {
“date_histogram”: {
“field”: “sold”,
“interval”: “month”,
“format”: “yyyy-MM-dd”
}
}
}
}
时间间隔要求是日历术语month (如每个 bucket 1 个月)。
我们提供日期格式(format)以便 buckets 的键值便于阅读。

min_doc_count 这个参数强制返回空 buckets。
extended_bounds 这个参数强制返回整年。
GET /cars/transactions/_search
{
“size” : 0,
“aggs”: {
“sales”: {
“date_histogram”: {
“field”: “sold”,
“interval”: “month”,
“format”: “yyyy-MM-dd”,
“min_doc_count” : 0,
“extended_bounds” : {
“min” : “2014-01-01”,
“max” : “2014-12-31”
}
}
}
}
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值