吃西瓜

走过必留下痕迹

目录
探索ElasticSearch-深入搜索之全文搜索(八)
/  

探索ElasticSearch-深入搜索之全文搜索(八)

前言

学习需要先打好基础,最后才能逐步深入。今天来重新探索下ElasticSearch的全文搜索。

搜索

ElasticSearch中存在两种搜索方式。一种是Request Body SearchRequest URL Search方式。Request URL Search是通过将参数放在URL之后来达到传递查询语句的目的,比如

GET /GET /kibana_sample_data_ecommerce/_search?q=customer_first_name:Eddie

另外一种是Request Body Search是通过将参数以json串的方式传递,相对于Request URL Search来说更加清晰,更够传递更加复杂的参数。一般在实际的使用中,Request Body Search会使用的多一些。下面主要讲一讲Request Body Search的方式来查询ElasticSearch

Query and filter context

本文使用的数据均为kibana中的kibana_sample_data_ecommerce数据。

ElasticSearch的查询API中存在两种主要的过滤方式。一种是Query,由query引导。另外一种是filter,由filter来引导。两者之间的区别是在query之后的查询子句,会对文档的分数产生影响。而filter之后的查询子句不会对文档的分数产生影响。

举个例子。

GET /kibana_sample_data_ecommerce/_search
{
  "query": {
    "bool": {
      "must": [
        {
          "match": {
            "customer_first_name": "Eddie"
          }
        }
      ],
      "filter": {
        "term": {
          "customer_full_name.keyword": "Eddie Underwood"
        }
      }
    }
  }
}    

可以看到该bool查询存在matchterm子查询。因为termfilter对象内,所以不会对最后的排序分数产生影响。而match子查询中的customer_first_name会对最后的排序分数产生影响。

Match All Query

match_all

match_all作为最简单的查询。一般不会在生产环境中使用,在测试环境中使用的会较多。match_all会查询出所有的文档。
举个例子。

GET /kibana_sample_data_ecommerce/_search
{
  "query": {
    "match_all": {}
  }
}

match_none

今天才发现居然存在这么个搜索。match_nonematch_all的反面,不会搜索到任何的文档。

GET /kibana_sample_data_ecommerce/_search
{
    "query": {
        "match_none": {}
    }
}

Full text queries

作为一个全文搜索引擎的意义,对于text字段使用全文搜索。最典型的应用是可以用来搜索文章(比如各大博客网站),用来搜索代码(比如Github)。

match Query

match查询是最典型的全文搜索的查询子句。match查询子句会将查询语句根据字段的分析器分析为多个单词。然后逐个查询文档中该字段是否存在。
举个例子。

GET /kibana_sample_data_ecommerce/_search
{
    "query": {
        "match": {
          "customer_full_name": "Eddie Weber"
        }
    }
}

可以得到

  "hits" : {
    "total" : 115,
    "hits" : [
      {
          "customer_full_name" : "Eddie Weber"
      }
]

customer_full_name会被分析为eddieweber两个单词。之后在文档中的customer_full_name中查询是否包含这两个字段。如果包含了这两个单词其中一个,那么就算是匹配成功。如果一个都没有包含,那么就表示匹配不成功。在示例数据中eddie或者weber匹配到了115个文档。

默认情况下匹配的算法的确跟上面一样,只要包含了一个单词就可以匹配上文档。但是,也可以通过参数operator来修改这个算法。比如下面指定and操作符。

GET /kibana_sample_data_ecommerce/_search
{
  "query": {
    "match": {
      "customer_full_name": {
        "query": "Eddie Weber",
        "operator": "and"
      }
    }
  }
}

只能匹配上两个文档。从原来的匹配115个文档降到了2个文档。

  "hits" : {
    "total" : 2,
    "hits" : [
        "_source" : {
          "customer_full_name" : "Eddie Weber",

这里表示必须customer_full_name必须既包含eddie也要包含weber才可以匹配上。

match Phrase Query

match Phrase表示短语搜索。当我们想要搜索一个短语的时候,可以使用match Phrase Query,比如我们还是想要搜索customer_full_nameEddie Webber的人。但是,我们不想搜索出来只叫做Eddie,也不想搜索出来叫做Eddie xxx Webber的人。这个时候可以使用match Phrase,因为match Phrase不仅会要求字段内容中均包含eddiewebber也要求这两个单词的顺序是一致的,中间不能有其他单词插入。

比如我们再插入一条数据,一个叫做Eddie fake Weber的人。

POST /kibana_sample_data_ecommerce/_doc/1
{
  "customer_full_name":"Eddie fake Weber"
}

这个时候,使用matchand来进行匹配会发现有三条数据。

 "hits" : {
    "total" : 3,
    "max_score" : 9.586426,
    "hits" : [
      {
          "customer_full_name" : "Eddie Weber"
      },
      {
      "customer_full_name":"Eddie Weber"
      },
      {
      "customer_full_name":"Eddie fake Weber"
      }

我们使用match Phrase Query来进行搜索。

GET /kibana_sample_data_ecommerce/_search
{
  "query": {
    "match_phrase": {
      "customer_full_name": "Eddie Weber"
    }
  }
}

就只会得到只有名字叫做Eddie Weber的人。

  "hits" : {
    "total" : 2,
    "max_score" : 9.586426,
    "hits" : [
      {
          "customer_full_name" : "Eddie Weber"
      },
      {
          "customer_full_name" : "Eddie Weber"
      }

ElasticSearch中还提供了一个叫做slop的参数。使用slop参数可以指定单词之间的最大间隔是多少。间隔指短语中单词与单词之间间隔了多少单词。比如上面的Eddie Weber中的EddieWeber没有间隔任何的单词,所以间隔为0。而新插入的数据Eddie fake Weber中的EddieWeber间隔为1,因为间隔了fake这个单词。
默认的match phraseslop的值为0。可以设置slop值为1来匹配上Eddie fake Weber

GET /kibana_sample_data_ecommerce/_search
{
  "query": {
    "match_phrase": {
      "customer_full_name": {
        "query": "Eddie Weber",
        "slop": 1
      }
      
    }
  }
}

可以匹配上三个文档。

 "hits" : {
    "total" : 3,
    "max_score" : 9.586426,
    "hits" : [
      {
          "customer_full_name" : "Eddie Weber"
      },
      {
      "customer_full_name":"Eddie Weber"
      },
      {
      "customer_full_name":"Eddie fake Weber"
      }

match搜索比较下可以发现match phrase类似于match加上and条件再加上顺序和间隔为0的条件。

match Phrase Prefix Query

match phrase prefixmatch phrase之间的区别是match phrase prefix可以让你在短语的最后一个单词上进行前缀匹配。比如还是想要搜索customer_full_name,这个时候我可能已经忘记了Eddie Weber的最后一个单词Weber的全部内容了。那么我可以使用match phrase prefix来搜索Eddie We,因为最后一个单词We会进行前缀匹配。所以,我还是能够搜索到Eddie Weber这个人。
比如

GET /kibana_sample_data_ecommerce/_search
{
  "query": {
    "match_phrase_prefix": {
      "customer_full_name": "Eddie We"
    }
  }
}

可以匹配上

  "hits" : {
    "total" : 2,
    "max_score" : 9.586426,
    "hits" : [
      {
          "customer_full_name" : "Eddie Weber"
      },
      {
          "customer_full_name" : "Eddie Weber"
      }

那么不是最后一个单词而是在之前的单词会进行前缀匹配吗?
比如我搜索Edd We

GET /kibana_sample_data_ecommerce/_search
{
  "query": {
    "match_phrase_prefix": {
      "customer_full_name": "Edd We"
    }
  }
}

匹配不上任何的文档。因为只会对最后一个单词进行前缀匹配。

  "hits" : {
    "total" : 0,
    "max_score" : null,
    "hits" : [ ]
  }

另外ElasticSearch还提供了max_expansions来控制最后一个前缀单词和需要匹配的单词之间的距离。什么意思?比如上面使用We来前缀匹配Weber。那么这两个单词之间的距离是ber,也就是3个字母的距离。

加入我们使用max_expansions来控制匹配的距离为2,看一下会不会匹配上Weber

关于写作

"百天"写作计划下半部。

每周更新一篇碎碎念。

每周三、周六更新一篇尽量全面,详细的文章。

可能时长突破了百天,但是又有什么关系呢?提高写作水平,形成写作的习惯才是最终的目的。

如果这篇文章给你带来了一些帮助,可以动动手指点个赞,顺便关注一波就更好了。

如果上面都没有,那么写下读完之后最想说的话?有效的反馈和你的鼓励是对我最大的帮助。

另外打算把博客给重新捡起来了。欢迎大家来访问吃西瓜

我是shane。今天是2019年9月18日。"百天"写作计划下半部,52/100。


标题:探索ElasticSearch-深入搜索之全文搜索(八)
作者:yang2yang
地址:http://blog.chixigua.xyz/articles/2019/09/18/1568819215068.html

评论