Elasticsearch整理笔记

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Elasticsearch整理笔记相关的知识,希望对你有一定的参考价值。


es中的查询请求有两种方式,一种是简易版的查询,另外一种是使用JSON完整的请求体,叫做结构化查询(DSL)。
由于DSL查询更为直观也更为简易,所以大都使用这种方式。
DSL查询是POST过去一个json,由于post的请求是json格式的,所以存在很多灵活性,也有很多形式。
这里有一个地方注意的是官方文档里面给的例子的json结构只是一部分,并不是可以直接黏贴复制进去使用的。一般要在外面加个query为key的机构。

match
最简单的一个match例子:

查询和"我的宝马多少马力"这个查询语句匹配的文档。

​​​​
​​"query"​​​​: ​​
​​"match"​​​​: ​​
​​"content"​​​​: ​​
​​"query"​​​​: ​​​​"我的宝马多少马力"​​
​​​​
​​​​
​​​​
​​​​

上面的查询匹配就会进行分词,比如"宝马多少马力"会被分词为"宝马 多少 马力", 所有有关"宝马 多少 马力", 那么所有包含这三个词中的一个或多个的文档就会被搜索出来。
并且根据lucene的评分机制(TF/IDF)来进行评分。

match_phrase
比如上面一个例子,一个文档"我的保时捷马力不错"也会被搜索出来,那么想要精确匹配所有同时包含"宝马 多少 马力"的文档怎么做?就要使用 match_phrase 了

​​​​
​​"query"​​​​: ​​
​​"match_phrase"​​​​: ​​
​​"content"​​​​: ​​
​​"query"​​​​: ​​​​"我的宝马多少马力"​​
​​​​
​​​​
​​​​
​​​​

完全匹配可能比较严,我们会希望有个可调节因子,少匹配一个也满足,那就需要使用到slop。

​​​​
​​"query"​​​​: ​​
​​"match_phrase"​​​​: ​​
​​"content"​​​​: ​​
​​"query"​​​​: ​​​​"我的宝马多少马力"​​​​,​​
​​"slop"​​​​: ​​​​1​​
​​​​
​​​​
​​​​
​​​​

multi_match
如果我们希望两个字段进行匹配,其中一个字段有这个文档就满足的话,使用multi_match

​​​​
​​"query"​​​​: ​​
​​"multi_match"​​​​: ​​
​​"query"​​​​: ​​​​"我的宝马多少马力"​​​​,​​
​​"fields"​​​​: [​​​​"title"​​​​, ​​​​"content"​​​​]​​
​​​​
​​​​
​​​​

但是multi_match就涉及到匹配评分的问题了。

我们希望完全匹配的文档占的评分比较高,则需要使用best_fields

​​​​
​​"query"​​​​: ​​
​​"multi_match"​​​​: ​​
​​"query"​​​​: ​​​​"我的宝马发动机多少"​​​​,​​
​​"type"​​​​: ​​​​"best_fields"​​​​,​​
​​"fields"​​​​: [​​
​​"tag"​​​​,​​
​​"content"​​
​​],​​
​​"tie_breaker"​​​​: ​​​​0.3​​
​​​​
​​​​
​​​​

意思就是完全匹配"宝马 发动机"的文档评分会比较靠前,如果只匹配宝马的文档评分乘以0.3的系数

我们希望越多字段匹配的文档评分越高,就要使用most_fields

​​​​
​​"query"​​​​: ​​
​​"multi_match"​​​​: ​​
​​"query"​​​​: ​​​​"我的宝马发动机多少"​​​​,​​
​​"type"​​​​: ​​​​"most_fields"​​​​,​​
​​"fields"​​​​: [​​
​​"tag"​​​​,​​
​​"content"​​
​​]​​
​​​​
​​​​
​​​​

我们会希望这个词条的分词词汇是分配到不同字段中的,那么就使用cross_fields

​​​​
​​"query"​​​​: ​​
​​"multi_match"​​​​: ​​
​​"query"​​​​: ​​​​"我的宝马发动机多少"​​​​,​​
​​"type"​​​​: ​​​​"cross_fields"​​​​,​​
​​"fields"​​​​: [​​
​​"tag"​​​​,​​
​​"content"​​
​​]​​
​​​​
​​​​
​​​​

term
term是代表完全匹配,即不进行分词器分析,文档中必须包含整个搜索的词汇

​​​​
​​"query"​​​​: ​​
​​"term"​​​​: ​​
​​"content"​​​​: ​​​​"汽车保养"​​
​​​​
​​​​
​​​​

查出的所有文档都包含"汽车保养"这个词组的词汇。

使用term要确定的是这个字段是否“被分析”(analyzed),默认的字符串是被分析的。

拿官网上的例子举例:

mapping是这样的:

​​PUT my_index ​​
​​"mappings"​​​​: ​​
​​"my_type"​​​​: ​​
​​"properties"​​​​: ​​
​​"full_text"​​​​: ​​
​​"type"​​​​: ​​​​"string"​​
​​,​​
​​"exact_value"​​​​: ​​
​​"type"​​​​: ​​​​"string"​​​​,​​
​​"index"​​​​: ​​​​"not_analyzed"​​
​​​​
​​​​
​​​​
​​​​
​​​​

 

​​PUT my_index / my_type / ​​​​1​​​ ​​​​
​​"full_text"​​​​: ​​​​"Quick Foxes!"​​​​,​​
​​"exact_value"​​​​: ​​​​"Quick Foxes!"​​
​​​​

其中的full_text是被分析过的,所以full_text的索引中存的就是[quick, foxes],而extra_value中存的是[Quick Foxes!]。

那下面的几个请求:

​​GET my_index / my_type / _search ​​
​​"query"​​​​: ​​
​​"term"​​​​: ​​
​​"exact_value"​​​​: ​​​​"Quick Foxes!"​​
​​​​
​​​​
​​​​

请求的出数据,因为完全匹配

​​GET my_index / my_type / _search ​​
​​"query"​​​​: ​​
​​"term"​​​​: ​​
​​"full_text"​​​​: ​​​​"Quick Foxes!"​​
​​​​
​​​​
​​​​

请求不出数据的,因为full_text分词后的结果中没有[Quick Foxes!]这个分词。

 

bool查询

filter:不参与评分的快速查询

​​GET _search ​​
​​"query"​​​​: ​​
​​"bool"​​​​: ​​
​​"filter"​​​​: ​​
​​"term"​​​​: ​​
​​"content"​​​​: ​​​​"宝马"​​
​​​​
​​​​
​​​​
​​​​
​​​​

range:范围过滤

​​GET _search ​​
​​"post_filter"​​​​:​​
​​"range"​​​​:​​
​​"price"​​​​:​​​​"gt"​​​​:​​​​35​​​​, ​​​​"lt"​​​​: ​​​​50​​​​​​
​​​​
​​​​
​​​​

exists:字段有值

​​查询price有值的, ​​​​null​​​​也不行​​
​​GET _search ​​
​​"post_filter"​​​​: ​​
​​"exists"​​​​: ​​
​​"field"​​​​: ​​​​"price"​​
​​​​
​​​​
​​​​

​​查询price有值的, ​​​​null​​​​也不行​​
​​GET _search ​​
​​"query"​​​​: ​​
​​"bool"​​​​: ​​
​​"filter"​​​​: ​​
​​"exists"​​​​: ​​
​​"field"​​​​: ​​​​"price"​​
​​​​
​​​​
​​​​
​​​​
​​​​

 

bool联合查询: must,should,must_not
如果我们想要请求"content中带宝马,但是tag中不带宝马"这样类似的需求,就需要用到bool联合查询。
联合查询就会使用到must,should,must_not三种关键词。

这三个可以这么理解

must: 文档必须完全匹配条件
should: should下面会带一个以上的条件,至少满足一个条件,这个文档就符合should
must_not: 文档必须不匹配条件
比如上面那个需求:

​​​​
​​"query"​​​​: ​​
​​"bool"​​​​: ​​
​​"must"​​​​: ​​
​​"term"​​​​: ​​
​​"content"​​​​: ​​​​"宝马"​​
​​​​
​​,​​
​​"must_not"​​​​: ​​
​​"term"​​​​: ​​
​​"tags"​​​​: ​​​​"宝马"​​
​​​​
​​​​
​​​​
​​​​
​​​​

聚合查询:

filtered查询

如果你想要找到所有售价高于10000美刀的车,同时也对这些车计算其平均价格,那么可以使用一个filtered查询:

​​GET _search?search_type=count​​
​​​​
​​"query"​​​ ​​: ​​
​​"filtered"​​​​: ​​
​​"filter"​​​​: ​​
​​"range"​​​​: ​​
​​"price"​​​​: ​​
​​"gte"​​​​: ​​​​10000​​
​​​​
​​​​
​​​​
​​​​
​​,​​
​​"aggs"​​​ ​​: ​​
​​"single_avg_price"​​​​: ​​
​​"avg"​​​ ​​: ​​​​"field"​​​ ​​: ​​​​"price"​​​ ​​​​
​​​​
​​​​
​​​​

 

从本质上而言,使用filtered查询和使用match查询并无区别,正如我们在上一章所讨论的那样。该查询(包含了一个过滤器)返回文档的一个特定子集,然后聚合工作在该子集上。

过滤桶(Filter Bucket)

如果你只想过滤聚合结果呢?假设我们正在创建针对汽车交易的搜索页面,我们想要根据用户搜索内容来展示对应结果。但是我们也想通过包含上个月出售的汽车的平均价格(匹配搜索的汽车)来让页面更加丰富。

此时我们不能使用简单的作用域,因为有两个不同搜索条件。搜索结果必须要匹配ford,但是聚合结果必须要匹配ford以及售出时间为上个月。

为了解决这一问题,我们使用一个名为filter的特殊桶。通过制定一个过滤器,当文档匹配了该过滤器的规则时,它就会被添加到桶中。

以下是得到的查询:

​​GET _search?search_type=count​​
​​​​
​​"query"​​​​:​​
​​"match"​​​​: ​​
​​"make"​​​​: ​​​​"ford"​​
​​​​
​​,​​
​​"aggs"​​​​:​​
​​"recent_sales"​​​​: ​​
​​"filter"​​​​: ​​
​​"range"​​​​: ​​
​​"sold"​​​​: ​​
​​"from"​​​​: ​​​​"now-1M"​​
​​​​
​​​​
​​,​​
​​"aggs"​​​​: ​​
​​"average_price"​​​​:​​
​​"avg"​​​​: ​​
​​"field"​​​​: ​​​​"price"​​
​​​​
​​​​
​​​​
​​​​
​​​​
​​​​

 

因为过滤器桶和任何其它桶以相似的方式工作,你可以任意地将其它桶和指标包含在其中。所有的嵌套组建都会”继承”该过滤器。从而使你能够根据需要对聚合中的内容进行过滤。

后置过滤器(Post Filter)

目前,我们有了用于过滤搜索结果和聚合的过滤器(filtered查询),也有了用于过滤聚合中某一部分的过滤器(filter桶)。

你也许会好奇,“是否有一种过滤器只过滤搜索结果,而不过滤聚合呢?”这个问题的答案就是使用post_filter。

它是搜索请求内能够接受一个过滤器作为参数的顶层元素。该过滤器会在查询执行完毕后生效(后置因此得名:在查询执行之后运行)。正因为它在查询执行后才会运行,所以它并不会影响查询作用域 - 因此就不会对聚合有所影响。

我们可以利用这一行为在搜索条件中添加额外的过滤器,而不影响用户界面中类似于类别分面(Categorical Facets)的元素。让我们设计另一个针对汽车交易的搜索页面。该页面允许用户对汽车进行搜索,同时还能够根据颜色进行过滤。颜色通过聚合提供:

​​GET _search?search_type=count​​
​​​​
​​"query"​​​​: ​​
​​"match"​​​​: ​​
​​"make"​​​​: ​​​​"ford"​​
​​​​
​​,​​
​​"post_filter"​​​​: ​​
​​"term"​​​ ​​: ​​
​​"color"​​​ ​​: ​​​​"green"​​
​​​​
​​,​​
​​"aggs"​​​ ​​: ​​
​​"all_colors"​​​​: ​​
​​"terms"​​​ ​​: ​​​​"field"​​​ ​​: ​​​​"color"​​​ ​​​​
​​​​
​​​​
​​​​

 

post_filter元素是一个顶层元素,只会对搜索结果进行过滤。

查询部分呢用来找到所有ford汽车。然后我们根据一个terms聚合来得到颜色列表。因为聚合是在查询作用域中进行的,得到的颜色列表会反映出ford汽车的各种颜色。

最后,post_filter会对搜索结果进行过滤,只显示绿色的ford汽车。这一步发生在执行查询之后,因此聚合是不会被影响的。

这一点对于维持一致的用户界面而言是非常重要的。假设一个用户在界面上点击了一个分类(比如,绿色)。期望的结果是搜索结果被过滤了,而用户界面上的分类选项是不会变化的。如果你使用了一个filtered查询,用户界面上也立即会对分类进行更新,此时绿色就变成了唯一的选项 - 这显然不是用户想要的!

只有当你需要对搜索结果和聚合使用不同的过滤方式时才考虑使用post_filter。有时一些用户会直接在常规搜索中使用post_filter。

不要这样做!post_filter会在查询之后才会被执行,因此会失去过滤在性能上帮助(比如缓存)。

post_filter应该只和聚合一起使用,并且仅当你使用了不同的过滤条件时。

选择合适类型的过滤 - 搜索结果(Search Hits),聚合(Aggregations),或两者 - 通常都取决于你的用户界面的行为。过滤器的选择(或者组合)取决于你想要如何向用户展示结果数据。

A filtered query affects both search results and aggregations.filtered查询会影响搜索结果和聚合。 
filter桶只影响聚合。 
post_filter只影响搜索结果。

 

关于排序、分页查询

​​GET _search​​
​​​​
​​"query"​​​​: ​​
​​"match_all"​​​​: ​​
​​,​​
​​"sort"​​​​: [​​
​​​​
​​"age"​​​​: ​​
​​"order"​​​​: ​​​​"desc"​​
​​​​
​​​​
​​],​​
​​"from"​​​​: ​​​​2​​​​,​​
​​"size"​​​​: ​​​​1​​
​​​​

 

以上是关于Elasticsearch整理笔记的主要内容,如果未能解决你的问题,请参考以下文章

ElasticSearch笔记整理:简介REST与安装配置

ElasticSearch笔记整理:Java API使用与ES中文分词

区块链技术与应用肖臻老师笔记整理之------17-ETH-交易树和收据树

ElasticSearch笔记整理:CURL操作ES插件集群安装与核心概念

基于hyperledger联盟链的汽车轨迹追溯系统

基于hyperledger联盟链的汽车轨迹追溯系统