ES搜索 term與match區別 bool查詢

一、ik_max_wordjavascript

會將文本作最細粒度的拆分,好比會將「中華人民共和國人民大會堂」拆分爲「中華人民共和國、中華人民、中華、華人、人民共和國、人民、共和國、大會堂、大會、會堂等詞語。java

二、ik_smart
會作最粗粒度的拆分,好比會將「中華人民共和國人民大會堂」拆分爲中華人民共和國、人民大會堂。
 elasticsearch

termmatch 總結

在實際的項目查詢中,termmatch 是最經常使用的兩個查詢,而常常搞不清二者有什麼區別,趁機總結有空總結下。code

term用法token

先看看term的定義,term是表明徹底匹配,也就是精確查詢,搜索前不會再對搜索詞進行分詞拆解。ip

這裏經過例子來講明,先存放一些數據:文檔


 

{
    "title": "love China",
    "content": "people very love China",
    "tags": ["China", "love"]
}
{
    "title": "love HuBei",
    "content": "people very love HuBei",
    "tags": ["HuBei", "love"]
}

來使用term 查詢下:it

{
  "query": {
    "term": {
      "title": "love"
    }
  }
}

結果是,上面的兩條數據都能查詢到:io

{
  "took": 1,
  "timed_out": false,
  "_shards": {
    "total": 5,
    "successful": 5,
    "skipped": 0,
    "failed": 0
  },
  "hits": {
    "total": 2,
    "max_score": 0.6931472,
    "hits": [
      {
        "_index": "test",
        "_type": "doc",
        "_id": "8",
        "_score": 0.6931472,
        "_source": {
          "title": "love HuBei",
          "content": "people very love HuBei",
          "tags": ["HuBei","love"]
        }
      },
      {
        "_index": "test",
        "_type": "doc",
        "_id": "7",
        "_score": 0.6931472,
        "_source": {
          "title": "love China",
          "content": "people very love China",
          "tags": ["China","love"]
        }
      }
    ]
  }
}

發現,title裏有關love的關鍵字都查出來了,可是我只想精確匹配 love China這個,按照下面的寫法看看能不能查出來:ast

{
  "query": {
    "term": {
      "title": "love China"
    }
  }
}

執行發現無數據,從概念上看,term屬於精確匹配,只能查單個詞。我想用term匹配多個詞怎麼作?可使用terms來:

{
  "query": {
    "terms": {
      "title": ["love", "China"]
    }
  }
}

查詢結果爲:

{
  "took": 1,
  "timed_out": false,
  "_shards": {
    "total": 5,
    "successful": 5,
    "skipped": 0,
    "failed": 0
  },
  "hits": {
    "total": 2,
    "max_score": 0.6931472,
    "hits": [
      {
        "_index": "test",
        "_type": "doc",
        "_id": "8",
        "_score": 0.6931472,
        "_source": {
          "title": "love HuBei",
          "content": "people very love HuBei",
          "tags": ["HuBei","love"]
        }
      },
      {
        "_index": "test",
        "_type": "doc",
        "_id": "7",
        "_score": 0.6931472,
        "_source": {
          "title": "love China",
          "content": "people very love China",
          "tags": ["China","love"]
        }
      }
    ]
  }
}

發現所有查詢出來,爲何?由於terms裏的[ ] 多個是或者的關係,只要知足其中一個詞就能夠。想要通知知足兩個詞的話,就得使用bool的must來作,以下:

{
  "query": {
    "bool": {
      "must": [
        {
          "term": {
            "title": "love"
          }
        },
        {
          "term": {
            "title": "china"
          }
        }
      ]
    }
  }
}

能夠看到,咱們上面使用china是小寫的。當使用的是大寫的China 咱們進行搜索的時候,發現搜不到任何信息。這是爲何了?title這個詞在進行存儲的時候,進行了分詞處理。咱們這裏使用的是默認的分詞處理器進行了分詞處理。咱們能夠看看如何進行分詞處理的?

分詞處理器

 

GET test/_analyze
{
  "text" : "love China"
}

結果爲:

 

{
  "tokens": [
    {
      "token": "love",
      "start_offset": 0,
      "end_offset": 4,
      "type": "<ALPHANUM>",
      "position": 0
    },
    {
      "token": "china",
      "start_offset": 5,
      "end_offset": 10,
      "type": "<ALPHANUM>",
      "position": 1
    }
  ]
}

分析出來的爲lovechina的兩個詞。而term只能完完整整的匹配上面的詞,不作任何改變的匹配。因此,咱們使用China這樣的方式進行的查詢的時候,就會失敗。稍後會有一節專門講解分詞器。

match 用法

先用 love China來匹配。

 

GET test/doc/_search
{
  "query": {
    "match": {
      "title": "love China"
    }
  }
}

結果是:

 

{
  "took": 1,
  "timed_out": false,
  "_shards": {
    "total": 5,
    "successful": 5,
    "skipped": 0,
    "failed": 0
  },
  "hits": {
    "total": 2,
    "max_score": 1.3862944,
    "hits": [
      {
        "_index": "test",
        "_type": "doc",
        "_id": "7",
        "_score": 1.3862944,
        "_source": {
          "title": "love China",
          "content": "people very love China",
          "tags": [
            "China",
            "love"
          ]
        }
      },
      {
        "_index": "test",
        "_type": "doc",
        "_id": "8",
        "_score": 0.6931472,
        "_source": {
          "title": "love HuBei",
          "content": "people very love HuBei",
          "tags": [
            "HuBei",
            "love"
          ]
        }
      }
    ]
  }
}

發現兩個都查出來了,爲何?由於match進行搜索的時候,會先進行分詞拆分,拆完後,再來匹配,上面兩個內容,他們title的詞條爲: love china hubei ,咱們搜索的爲love China 咱們進行分詞處理獲得爲love china ,而且屬於或的關係,只要任何一個詞條在裏面就能匹配到。若是想 loveChina 同時匹配到的話,怎麼作?使用 match_phrase

match_phrase 用法

match_phrase 稱爲短語搜索,要求全部的分詞必須同時出如今文檔中,同時位置必須緊鄰一致。

 

GET test/doc/_search
{
  "query": {
    "match_phrase": {
      "title": "love china"
    }
  }
}

結果爲:

 

{
  "took": 5,
  "timed_out": false,
  "_shards": {
    "total": 5,
    "successful": 5,
    "skipped": 0,
    "failed": 0
  },
  "hits": {
    "total": 1,
    "max_score": 1.3862944,
    "hits": [
      {
        "_index": "test",
        "_type": "doc",
        "_id": "7",
        "_score": 1.3862944,
        "_source": {
          "title": "love China",
          "content": "people very love China",
          "tags": [
            "China",
            "love"
          ]
        }
      }
    ]
  }
}

此次好像符合咱們的需求了,結果只出現了一條記錄。

 

bool查詢的使用

Bool查詢對應Lucene中的BooleanQuery,它由一個或者多個子句組成,每一個子句都有特定的類型。

must

返回的文檔必須知足must子句的條件,而且參與計算分值

filter

返回的文檔必須知足filter子句的條件。可是不會像Must同樣,參與計算分值

should

返回的文檔可能知足should子句的條件。在一個Bool查詢中,若是沒有must或者filter,有一個或者多個should子句,那麼只要知足一個就能夠返回。minimum_should_match參數定義了至少知足幾個子句。

must_nout

返回的文檔必須不知足must_not定義的條件。

若是一個查詢既有filter又有should,那麼至少包含一個should子句。

 

bool查詢也支持禁用協同計分選項disable_coord。通常計算分值的因素取決於全部的查詢條件。

bool查詢也是採用more_matches_is_better的機制,所以知足must和should子句的文檔將會合並起來計算分值。

{
    "bool" : {
        "must" : {
            "term" : { "user" : "kimchy" }
        },
        "filter": {
            "term" : { "tag" : "tech" }
        },
        "must_not" : {
            "range" : {
                "age" : { "from" : 10, "to" : 20 }
            }
        },
        "should" : [
            {
                "term" : { "tag" : "wow" }
            },
            {
                "term" : { "tag" : "elasticsearch" }
            }
        ],
        "minimum_should_match" : 1,
        "boost" : 1.0
    }
}

bool.filter的分值計算

在filter子句查詢中,分值將會都返回0。分值會受特定的查詢影響。

好比,下面三個查詢中都是返回全部status字段爲active的文檔

第一個查詢,全部的文檔都會返回0:

GET _search
{
  "query": {
    "bool": {
      "filter": {
        "term": {
          "status": "active"
        }
      }
    }
  }
}

下面的bool查詢中包含了一個match_all,所以全部的文檔都會返回1

GET _search
{
  "query": {
    "bool": {
      "must": {
        "match_all": {}
      },
      "filter": {
        "term": {
          "status": "active"
        }
      }
    }
  }
}

constant_score與上面的查詢結果相同,也會給每一個文檔返回1:

GET _search
{
  "query": {
    "constant_score": {
      "filter": {
        "term": {
          "status": "active"
        }
      }
    }
  }
}

使用named query給子句添加標記

若是想知道究竟是bool裏面哪一個條件匹配,可使用named query查詢:

{
    "bool" : {
        "should" : [
            {"match" : { "name.first" : {"query" : "shay", "_name" : "first"} }},
            {"match" : { "name.last" : {"query" : "banon", "_name" : "last"} }}
        ],
        "filter" : {
            "terms" : {
                "name.last" : ["banon", "kimchy"],
                "_name" : "test"
            }
        }
    }
}