Elasticsearch整理笔记(三)

部分内容转载于

https://www.cnblogs.com/fengda/p/10348616.html

https://blog.csdn.net/ctwy291314/article/details/82744680

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

match
最简单的一个match例子:

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

{

    "query": {

        "match": {

            "content": {

                "query""我的宝马多少马力"

扫描二维码关注公众号,回复: 15938583 查看本文章

            }

        }

    }

}


上面的查询匹配就会进行分词,比如"宝马多少马力"会被分词为"宝马 多少 马力", 所有有关"宝马 多少 马力", 那么所有包含这三个词中的一个或多个的文档就会被搜索出来。
并且根据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

}

猜你喜欢

转载自blog.csdn.net/sm9sun/article/details/108602960