elasticsearch之布爾查詢


elasticsearch之布爾查詢

前言

布爾查詢是最常用的組合查詢,根據子查詢的規則,只有當文檔滿足所有子查詢條件時,elasticsearch引擎才將結果返回。布爾查詢支持的子查詢條件共4中:

  • must(and)
  • should(or)
  • must_not(not)
  • filter

下面我們來看看每個子查詢條件都是怎么玩的。

准備數據

PUT zhifou/doc/1
{
  "name":"顧老二",
  "age":30,
  "from": "gu",
  "desc": "皮膚黑、武器長、性格直",
  "tags": ["黑", "長", "直"]
}

PUT zhifou/doc/2
{
  "name":"大娘子",
  "age":18,
  "from":"sheng",
  "desc":"膚白貌美,嬌憨可愛",
  "tags":["白", "富","美"]
}

PUT zhifou/doc/3
{
  "name":"龍套偏房",
  "age":22,
  "from":"gu",
  "desc":"mmp,沒怎么看,不知道怎么形容",
  "tags":["造數據", "真","難"]
}


PUT zhifou/doc/4
{
  "name":"石頭",
  "age":29,
  "from":"gu",
  "desc":"粗中有細,狐假虎威",
  "tags":["粗", "大","猛"]
}

PUT zhifou/doc/5
{
  "name":"魏行首",
  "age":25,
  "from":"廣雲台",
  "desc":"仿佛兮若輕雲之蔽月,飄飄兮若流風之回雪,mmp,最后竟然沒有嫁給顧老二!",
  "tags":["閉月","羞花"]
}

must

現在,我們用布爾查詢所有from屬性為gu的數據:

GET zhifou/doc/_search
{
  "query": {
    "bool": {
      "must": [
        {
          "match": {
            "from": "gu"
          }
        }
      ]
    }
  }
}

上例中,我們通過在bool屬性(字段)內使用must來作為查詢條件,那么條件是什么呢?條件同樣被match包圍,就是fromgu的所有數據。
這里需要注意的是must字段對應的是個列表,也就是說可以有多個並列的查詢條件,一個文檔滿足各個子條件后才最終返回。

結果如下:

{
  "took" : 1,
  "timed_out" : false,
  "_shards" : {
    "total" : 5,
    "successful" : 5,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : 3,
    "max_score" : 0.6931472,
    "hits" : [
      {
        "_index" : "zhifou",
        "_type" : "doc",
        "_id" : "4",
        "_score" : 0.6931472,
        "_source" : {
          "name" : "石頭",
          "age" : 29,
          "from" : "gu",
          "desc" : "粗中有細,狐假虎威",
          "tags" : [
            "粗",
            "大",
            "猛"
          ]
        }
      },
      {
        "_index" : "zhifou",
        "_type" : "doc",
        "_id" : "1",
        "_score" : 0.2876821,
        "_source" : {
          "name" : "顧老二",
          "age" : 30,
          "from" : "gu",
          "desc" : "皮膚黑、武器長、性格直",
          "tags" : [
            "黑",
            "長",
            "直"
          ]
        }
      },
      {
        "_index" : "zhifou",
        "_type" : "doc",
        "_id" : "3",
        "_score" : 0.2876821,
        "_source" : {
          "name" : "龍套偏房",
          "age" : 22,
          "from" : "gu",
          "desc" : "mmp,沒怎么看,不知道怎么形容",
          "tags" : [
            "造數據",
            "真",
            "難"
          ]
        }
      }
    ]
  }
}

上例中,可以看到,所有from屬性為gu的數據查詢出來了。

那么,我們想要查詢fromgu,並且age30的數據怎么搞呢?

GET zhifou/doc/_search
{
  "query": {
    "bool": {
      "must": [
        {
          "match": {
            "from": "gu"
          }
        },
        {
          "match": {
            "age": 30
          }
        }
      ]
    }
  }
}

上例中,在must列表中,在增加一個age30的條件。

結果如下:

{
  "took" : 8,
  "timed_out" : false,
  "_shards" : {
    "total" : 5,
    "successful" : 5,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : 1,
    "max_score" : 1.287682,
    "hits" : [
      {
        "_index" : "zhifou",
        "_type" : "doc",
        "_id" : "1",
        "_score" : 1.287682,
        "_source" : {
          "name" : "顧老二",
          "age" : 30,
          "from" : "gu",
          "desc" : "皮膚黑、武器長、性格直",
          "tags" : [
            "黑",
            "長",
            "直"
          ]
        }
      }
    ]
  }
}

上例,符合條件的數據被成功查詢出來了。

注意:現在你可能慢慢發現一個現象,所有屬性值為列表的,都可以實現多個條件並列存在

should

那么,如果要查詢只要是fromgu或者tags閉月的數據怎么搞?

GET zhifou/doc/_search
{
  "query": {
    "bool": {
      "should": [
        {
          "match": {
            "from": "gu"
          }
        },
        {
          "match": {
            "tags": "閉月"
          }
        }
      ]
    }
  }
}

上例中,或關系的不能用must的了,而是要用should,只要符合其中一個條件就返回。

結果如下:

{
  "took" : 1,
  "timed_out" : false,
  "_shards" : {
    "total" : 5,
    "successful" : 5,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : 4,
    "max_score" : 0.6931472,
    "hits" : [
      {
        "_index" : "zhifou",
        "_type" : "doc",
        "_id" : "4",
        "_score" : 0.6931472,
        "_source" : {
          "name" : "石頭",
          "age" : 29,
          "from" : "gu",
          "desc" : "粗中有細,狐假虎威",
          "tags" : [
            "粗",
            "大",
            "猛"
          ]
        }
      },
      {
        "_index" : "zhifou",
        "_type" : "doc",
        "_id" : "5",
        "_score" : 0.5753642,
        "_source" : {
          "name" : "魏行首",
          "age" : 25,
          "from" : "廣雲台",
          "desc" : "仿佛兮若輕雲之蔽月,飄飄兮若流風之回雪,mmp,最后竟然沒有嫁給顧老二!",
          "tags" : [
            "閉月",
            "羞花"
          ]
        }
      },
      {
        "_index" : "zhifou",
        "_type" : "doc",
        "_id" : "1",
        "_score" : 0.2876821,
        "_source" : {
          "name" : "顧老二",
          "age" : 30,
          "from" : "gu",
          "desc" : "皮膚黑、武器長、性格直",
          "tags" : [
            "黑",
            "長",
            "直"
          ]
        }
      },
      {
        "_index" : "zhifou",
        "_type" : "doc",
        "_id" : "3",
        "_score" : 0.2876821,
        "_source" : {
          "name" : "龍套偏房",
          "age" : 22,
          "from" : "gu",
          "desc" : "mmp,沒怎么看,不知道怎么形容",
          "tags" : [
            "造數據",
            "真",
            "難"
          ]
        }
      }
    ]
  }
}

返回了所有符合條件的結果。

must_not

那么,如果我想要查詢from既不是gu並且tags也不是可愛,還有age不是18的數據怎么辦?

GET zhifou/doc/_search
{
  "query": {
    "bool": {
      "must_not": [
        {
          "match": {
            "from": "gu"
          }
        },
        {
          "match": {
            "tags": "可愛"
          }
        },
        {
          "match": {
            "age": 18
          }
        }
      ]
    }
  }
}

上例中,mustshould都不能使用,而是使用must_not,又在內增加了一個age18的條件。

結果如下:

{
  "took" : 9,
  "timed_out" : false,
  "_shards" : {
    "total" : 5,
    "successful" : 5,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : 1,
    "max_score" : 1.0,
    "hits" : [
      {
        "_index" : "zhifou",
        "_type" : "doc",
        "_id" : "5",
        "_score" : 1.0,
        "_source" : {
          "name" : "魏行首",
          "age" : 25,
          "from" : "廣雲台",
          "desc" : "仿佛兮若輕雲之蔽月,飄飄兮若流風之回雪,mmp,最后竟然沒有嫁給顧老二!",
          "tags" : [
            "閉月",
            "羞花"
          ]
        }
      }
    ]
  }
}

上例中,只有魏行首這一條數據,因為只有魏行首既不是顧家的人,標簽沒有可愛那一項,年齡也不等於18!
這里有點需要補充,條件中age對應的18你寫成整形還是字符串都沒啥......讓灑家感受到一種比Python還自由奔放的氣息!像極了JavaScript!

filter

那么,如果要查詢fromguage大於25的數據怎么查?

GET zhifou/doc/_search
{
  "query": {
    "bool": {
      "must": [
        {
          "match": {
            "from": "gu"
          }
        }
      ],
      "filter": {
        "range": {
          "age": {
            "gt": 25
          }
        }
      }
    }
  }
}

這里就用到了filter條件過濾查詢,過濾條件的范圍用range表示,gt表示大於,大於多少呢?是25。

結果如下:

{
  "took" : 2,
  "timed_out" : false,
  "_shards" : {
    "total" : 5,
    "successful" : 5,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : 2,
    "max_score" : 0.6931472,
    "hits" : [
      {
        "_index" : "zhifou",
        "_type" : "doc",
        "_id" : "4",
        "_score" : 0.6931472,
        "_source" : {
          "name" : "石頭",
          "age" : 29,
          "from" : "gu",
          "desc" : "粗中有細,狐假虎威",
          "tags" : [
            "粗",
            "大",
            "猛"
          ]
        }
      },
      {
        "_index" : "zhifou",
        "_type" : "doc",
        "_id" : "1",
        "_score" : 0.2876821,
        "_source" : {
          "name" : "顧老二",
          "age" : 30,
          "from" : "gu",
          "desc" : "皮膚黑、武器長、性格直",
          "tags" : [
            "黑",
            "長",
            "直"
          ]
        }
      }
    ]
  }
}

上例中,age大於25的條件都已經篩選出來了。

那么要查詢fromguage大於等於30的數據呢?

GET zhifou/doc/_search
{
  "query": {
    "bool": {
      "must": [
        {
          "match": {
            "from": "gu"
          }
        }
      ],
      "filter": {
        "range": {
          "age": {
            "gte": 30
          }
        }
      }
    }
  }
}

上例中,大於等於用gte表示。

結果如下:

{
  "took" : 0,
  "timed_out" : false,
  "_shards" : {
    "total" : 5,
    "successful" : 5,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : 1,
    "max_score" : 0.2876821,
    "hits" : [
      {
        "_index" : "zhifou",
        "_type" : "doc",
        "_id" : "1",
        "_score" : 0.2876821,
        "_source" : {
          "name" : "顧老二",
          "age" : 30,
          "from" : "gu",
          "desc" : "皮膚黑、武器長、性格直",
          "tags" : [
            "黑",
            "長",
            "直"
          ]
        }
      }
    ]
  }
}

那么,要查詢age小於25的呢?

GET zhifou/doc/_search
{
  "query": {
    "bool": {
      "filter": {
        "range": {
          "age": {
            "lt": 25
          }
        }
      }
    }
  }
}

上例中,小於用lt表示,結果如下:

{
  "took" : 1,
  "timed_out" : false,
  "_shards" : {
    "total" : 5,
    "successful" : 5,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : 2,
    "max_score" : 0.0,
    "hits" : [
      {
        "_index" : "zhifou",
        "_type" : "doc",
        "_id" : "2",
        "_score" : 0.0,
        "_source" : {
          "name" : "大娘子",
          "age" : 18,
          "from" : "sheng",
          "desc" : "膚白貌美,嬌憨可愛",
          "tags" : [
            "白",
            "富",
            "美"
          ]
        }
      },
      {
        "_index" : "zhifou",
        "_type" : "doc",
        "_id" : "3",
        "_score" : 0.0,
        "_source" : {
          "name" : "龍套偏房",
          "age" : 22,
          "from" : "gu",
          "desc" : "mmp,沒怎么看,不知道怎么形容",
          "tags" : [
            "造數據",
            "真",
            "難"
          ]
        }
      }
    ]
  }
}

在查詢一個age小於等於18的怎么辦呢?

GET zhifou/doc/_search
{
  "query": {
    "bool": {
      "filter": {
        "range": {
          "age": {
            "lte": 18
          }
        }
      }
    }
  }
}

上例中,小於等於用lte表示。結果如下:

{
  "took" : 0,
  "timed_out" : false,
  "_shards" : {
    "total" : 5,
    "successful" : 5,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : 1,
    "max_score" : 0.0,
    "hits" : [
      {
        "_index" : "zhifou",
        "_type" : "doc",
        "_id" : "2",
        "_score" : 0.0,
        "_source" : {
          "name" : "大娘子",
          "age" : 18,
          "from" : "sheng",
          "desc" : "膚白貌美,嬌憨可愛",
          "tags" : [
            "白",
            "富",
            "美"
          ]
        }
      }
    ]
  }
}

要查詢fromguage25~30之間的怎么查?

GET zhifou/doc/_search
{
  "query": {
    "bool": {
      "must": [
        {
          "match": {
            "from": "gu"
          }
        }
      ],
      "filter": {
        "range": {
          "age": {
            "gte": 25,
            "lte": 30
          }
        }
      }
    }
  }
}

上例中,使用ltegte來限定范圍。結果如下:

{
  "took" : 1,
  "timed_out" : false,
  "_shards" : {
    "total" : 5,
    "successful" : 5,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : 2,
    "max_score" : 0.6931472,
    "hits" : [
      {
        "_index" : "zhifou",
        "_type" : "doc",
        "_id" : "4",
        "_score" : 0.6931472,
        "_source" : {
          "name" : "石頭",
          "age" : 29,
          "from" : "gu",
          "desc" : "粗中有細,狐假虎威",
          "tags" : [
            "粗",
            "大",
            "猛"
          ]
        }
      },
      {
        "_index" : "zhifou",
        "_type" : "doc",
        "_id" : "1",
        "_score" : 0.2876821,
        "_source" : {
          "name" : "顧老二",
          "age" : 30,
          "from" : "gu",
          "desc" : "皮膚黑、武器長、性格直",
          "tags" : [
            "黑",
            "長",
            "直"
          ]
        }
      }
    ]
  }
}

那么,要查詢fromshengage小於等於25的怎么查呢?其實結果,我們可能已經想到了,只有一條,因為只有盛家小六符合結果。

GET zhifou/doc/_search
{
  "query": {
    "bool": {
      "must": [
        {
          "match": {
            "from": "sheng"
          }
        }
      ],
      "filter": {
        "range": {
          "age": {
            "lte": 25
          }
        }
      }
    }
  }
}

結果果然不出灑家所料!

{
  "took" : 0,
  "timed_out" : false,
  "_shards" : {
    "total" : 5,
    "successful" : 5,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : 1,
    "max_score" : 0.6931472,
    "hits" : [
      {
        "_index" : "zhifou",
        "_type" : "doc",
        "_id" : "2",
        "_score" : 0.6931472,
        "_source" : {
          "name" : "大娘子",
          "age" : 18,
          "from" : "sheng",
          "desc" : "膚白貌美,嬌憨可愛",
          "tags" : [
            "白",
            "富",
            "美"
          ]
        }
      }
    ]
  }
}

但是,灑家手一抖,將must換為should看看會發生什么?

GET zhifou/doc/_search
{
  "query": {
    "bool": {
      "should": [
        {
          "match": {
            "from": "sheng"
          }
        }
      ],
      "filter": {
        "range": {
          "age": {
            "lte": 25
          }
        }
      }
    }
  }
}

結果如下:

{
  "took" : 1,
  "timed_out" : false,
  "_shards" : {
    "total" : 5,
    "successful" : 5,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : 3,
    "max_score" : 0.6931472,
    "hits" : [
      {
        "_index" : "zhifou",
        "_type" : "doc",
        "_id" : "2",
        "_score" : 0.6931472,
        "_source" : {
          "name" : "大娘子",
          "age" : 18,
          "from" : "sheng",
          "desc" : "膚白貌美,嬌憨可愛",
          "tags" : [
            "白",
            "富",
            "美"
          ]
        }
      },
      {
        "_index" : "zhifou",
        "_type" : "doc",
        "_id" : "5",
        "_score" : 0.0,
        "_source" : {
          "name" : "魏行首",
          "age" : 25,
          "from" : "廣雲台",
          "desc" : "仿佛兮若輕雲之蔽月,飄飄兮若流風之回雪,mmp,最后竟然沒有嫁給顧老二!",
          "tags" : [
            "閉月",
            "羞花"
          ]
        }
      },
      {
        "_index" : "zhifou",
        "_type" : "doc",
        "_id" : "3",
        "_score" : 0.0,
        "_source" : {
          "name" : "龍套偏房",
          "age" : 22,
          "from" : "gu",
          "desc" : "mmp,沒怎么看,不知道怎么形容",
          "tags" : [
            "造數據",
            "真",
            "難"
          ]
        }
      }
    ]
  }
}

結果有點出乎意料,因為龍套偏房和魏行首不屬於盛家,但也被查詢出來了。那你要問了,怎么肥四?小老弟!這是因為在查詢過程中,優先經過filter過濾,因為should是或關系,龍套偏房和魏行首的年齡符合了filter過濾條件,也就被放行了!所以,如果在filter過濾條件中使用should的話,結果可能不會盡如人意!建議使用must代替

注意:filter工作於bool查詢內。比如我們將剛才的查詢條件改一下,把filterbool中挪出來。

GET zhifou/doc/_search
{
  "query": {
    "bool": {
      "must": [
        {
          "match": {
            "from": "sheng"
          }
        }
      ]
    },
    "filter": {
      "range": {
        "age": {
          "lte": 25
        }
      }
    }
  }
}

如上例所示,我們將filterbool平級,看查詢結果:

{
  "error": {
    "root_cause": [
      {
        "type": "parsing_exception",
        "reason": "[bool] malformed query, expected [END_OBJECT] but found [FIELD_NAME]",
        "line": 12,
        "col": 5
      }
    ],
    "type": "parsing_exception",
    "reason": "[bool] malformed query, expected [END_OBJECT] but found [FIELD_NAME]",
    "line": 12,
    "col": 5
  },
  "status": 400
}

結果報錯了!所以,filter工作位置很重要。

小結:

  • must:與關系,相當於關系型數據庫中的and
  • should:或關系,相當於關系型數據庫中的or
  • must_not:非關系,相當於關系型數據庫中的not
  • filter:過濾條件。
  • range:條件篩選范圍。
  • gt:大於,相當於關系型數據庫中的>
  • gte:大於等於,相當於關系型數據庫中的>=
  • lt:小於,相當於關系型數據庫中的<
  • lte:小於等於,相當於關系型數據庫中的<=

歡迎斧正,that's all

 
 
 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM