Elasticsearch(三):索引查詢

Gooooa發表於2020-10-21

原文來源自黑馬的課程

3.索引查詢(使用kibana的控制檯操作)

從4塊來講查詢:

  • 基本查詢
  • _source過濾
  • 結果過濾
  • 高階查詢
  • 排序

3.1.基本查詢:

基本語法

GET /索引庫名/_search
{
    "query":{
        "查詢型別":{
            "查詢條件":"查詢條件值"
        }
    }
}

這裡的query代表一個查詢物件,裡面可以有不同的查詢屬性

  • 查詢型別:
    • 例如:match_allmatchtermrange 等等
  • 查詢條件:查詢條件會根據型別的不同,寫法也有差異,後面詳細講解

3.1.1 查詢所有(match_all)

示例:

GET /heima/_search
{
    "query":{
        "match_all": {}
    }
}
  • query:代表查詢物件
  • match_all:代表查詢所有

結果:

{
  "took": 2,
  "timed_out": false,
  "_shards": {
    "total": 3,
    "successful": 3,
    "skipped": 0,
    "failed": 0
  },
  "hits": {
    "total": 2,
    "max_score": 1,
    "hits": [
      {
        "_index": "heima",
        "_type": "goods",
        "_id": "2",
        "_score": 1,
        "_source": {
          "title": "大米手機",
          "images": "http://image.leyou.com/12479122.jpg",
          "price": 2899
        }
      },
      {
        "_index": "heima",
        "_type": "goods",
        "_id": "r9c1KGMBIhaxtY5rlRKv",
        "_score": 1,
        "_source": {
          "title": "小米手機",
          "images": "http://image.leyou.com/12479122.jpg",
          "price": 2699
        }
      }
    ]
  }
}
  • took:查詢花費時間,單位是毫秒
  • time_out:是否超時
  • _shards:分片資訊
  • hits:搜尋結果總覽物件
    • total:搜尋到的總條數
    • max_score:所有結果中文件得分的最高分
    • hits:搜尋結果的文件物件陣列,每個元素是一條搜尋到的文件資訊
      • _index:索引庫
      • _type:文件型別
      • _id:文件id
      • _score:文件得分
      • _source:文件的源資料

3.1.2 匹配查詢(match)

我們先加入一條資料,便於測試:

PUT /heima/goods/3
{
    "title":"小米電視4A",
    "images":"http://image.leyou.com/12479122.jpg",
    "price":3899.00
}

現在,索引庫中有2部手機,1臺電視:

在這裡插入圖片描述

  • or關係

match型別查詢,會把查詢條件進行分詞,然後進行查詢,多個詞條之間是or的關係

GET /heima/_search
{
    "query":{
        "match":{
            "title":"小米電視"
        }
    }
}

結果:

"hits": {
    "total": 2,
    "max_score": 0.6931472,
    "hits": [
        {
            "_index": "heima",
            "_type": "goods",
            "_id": "tmUBomQB_mwm6wH_EC1-",
            "_score": 0.6931472,
            "_source": {
                "title": "小米手機",
                "images": "http://image.leyou.com/12479122.jpg",
                "price": 2699
            }
        },
        {
            "_index": "heima",
            "_type": "goods",
            "_id": "3",
            "_score": 0.5753642,
            "_source": {
                "title": "小米電視4A",
                "images": "http://image.leyou.com/12479122.jpg",
                "price": 3899
            }
        }
    ]
}

在上面的案例中,不僅會查詢到電視,而且與小米相關的都會查詢到,多個詞之間是or的關係。

  • and關係

某些情況下,我們需要更精確查詢,我們希望這個關係變成and,可以這樣做:

GET /heima/_search
{
    "query":{
        "match": {
          "title": {
            "query": "小米電視",
            "operator": "and"
          }
        }
    }
}

結果:

{
  "took": 2,
  "timed_out": false,
  "_shards": {
    "total": 3,
    "successful": 3,
    "skipped": 0,
    "failed": 0
  },
  "hits": {
    "total": 1,
    "max_score": 0.5753642,
    "hits": [
      {
        "_index": "heima",
        "_type": "goods",
        "_id": "3",
        "_score": 0.5753642,
        "_source": {
          "title": "小米電視4A",
          "images": "http://image.leyou.com/12479122.jpg",
          "price": 3899
        }
      }
    ]
  }
}

本例中,只有同時包含小米電視的詞條才會被搜尋到。

  • or和and之間?

orand 間二選一有點過於非黑即白。 如果使用者給定的條件分詞後有 5 個查詢詞項,想查詢只包含其中 4 個詞的文件,該如何處理?將 operator 操作符引數設定成 and 只會將此文件排除。

有時候這正是我們期望的,但在全文搜尋的大多數應用場景下,我們既想包含那些可能相關的文件,同時又排除那些不太相關的。換句話說,我們想要處於中間某種結果。

match 查詢支援 minimum_should_match 最小匹配引數, 這讓我們可以指定必須匹配的詞項數用來表示一個文件是否相關。我們可以將其設定為某個具體數字,更常用的做法是將其設定為一個百分數,因為我們無法控制使用者搜尋時輸入的單詞數量:

GET /heima/_search
{
    "query":{
        "match":{
            "title":{
            	"query":"小米曲面電視",
            	"minimum_should_match": "75%"
            }
        }
    }
}

本例中,搜尋語句可以分為3個詞,如果使用and關係,需要同時滿足3個詞才會被搜尋到。這裡我們採用最小品牌數:75%,那麼也就是說只要匹配到總詞條數量的75%即可,這裡3*75% 約等於2。所以只要包含2個詞條就算滿足條件了。

結果:

在這裡插入圖片描述

3.1.3 多欄位查詢(multi_match)

multi_matchmatch類似,不同的是它可以在多個欄位中查詢

GET /heima/_search
{
    "query":{
        "multi_match": {
            "query":    "小米",
            "fields":   [ "title", "subTitle" ]
        }
	}
}

本例中,我們會在title欄位和subtitle欄位中查詢小米這個詞

3.1.4 詞條匹配(term)

term 查詢被用於精確值 匹配,這些精確值可能是數字、時間、布林或者那些未分詞的字串

GET /heima/_search
{
    "query":{
        "term":{
            "price":2699.00
        }
    }
}

結果:

{
  "took": 2,
  "timed_out": false,
  "_shards": {
    "total": 3,
    "successful": 3,
    "skipped": 0,
    "failed": 0
  },
  "hits": {
    "total": 1,
    "max_score": 1,
    "hits": [
      {
        "_index": "heima",
        "_type": "goods",
        "_id": "r9c1KGMBIhaxtY5rlRKv",
        "_score": 1,
        "_source": {
          "title": "小米手機",
          "images": "http://image.leyou.com/12479122.jpg",
          "price": 2699
        }
      }
    ]
  }
}

3.1.5 多詞條精確匹配(terms)

terms 查詢和 term 查詢一樣,但它允許你指定多值進行匹配。如果這個欄位包含了指定值中的任何一個值,那麼這個文件滿足條件:

GET /heima/_search
{
    "query":{
        "terms":{
            "price":[2699.00,2899.00,3899.00]
        }
    }
}

結果:

{
  "took": 4,
  "timed_out": false,
  "_shards": {
    "total": 3,
    "successful": 3,
    "skipped": 0,
    "failed": 0
  },
  "hits": {
    "total": 3,
    "max_score": 1,
    "hits": [
      {
        "_index": "heima",
        "_type": "goods",
        "_id": "2",
        "_score": 1,
        "_source": {
          "title": "大米手機",
          "images": "http://image.leyou.com/12479122.jpg",
          "price": 2899
        }
      },
      {
        "_index": "heima",
        "_type": "goods",
        "_id": "r9c1KGMBIhaxtY5rlRKv",
        "_score": 1,
        "_source": {
          "title": "小米手機",
          "images": "http://image.leyou.com/12479122.jpg",
          "price": 2699
        }
      },
      {
        "_index": "heima",
        "_type": "goods",
        "_id": "3",
        "_score": 1,
        "_source": {
          "title": "小米電視4A",
          "images": "http://image.leyou.com/12479122.jpg",
          "price": 3899
        }
      }
    ]
  }
}

3.2.結果過濾

預設情況下,elasticsearch在搜尋的結果中,會把文件中儲存在_source的所有欄位都返回。

如果我們只想獲取其中的部分欄位,我們可以新增_source的過濾

3.2.1.直接指定欄位

示例:

GET /heima/_search
{
  "_source": ["title","price"],
  "query": {
    "term": {
      "price": 2699
    }
  }
}

返回的結果:

{
  "took": 12,
  "timed_out": false,
  "_shards": {
    "total": 3,
    "successful": 3,
    "skipped": 0,
    "failed": 0
  },
  "hits": {
    "total": 1,
    "max_score": 1,
    "hits": [
      {
        "_index": "heima",
        "_type": "goods",
        "_id": "r9c1KGMBIhaxtY5rlRKv",
        "_score": 1,
        "_source": {
          "price": 2699,
          "title": "小米手機"
        }
      }
    ]
  }
}

3.2.2.指定includes和excludes

我們也可以通過:

  • includes:來指定想要顯示的欄位
  • excludes:來指定不想要顯示的欄位

二者都是可選的。

示例:

GET /heima/_search
{
  "_source": {
    "includes":["title","price"]
  },
  "query": {
    "term": {
      "price": 2699
    }
  }
}

與下面的結果將是一樣的:

GET /heima/_search
{
  "_source": {
     "excludes": ["images"]
  },
  "query": {
    "term": {
      "price": 2699
    }
  }
}

3.3 高階查詢

3.3.1 布林組合(bool)

bool把各種其它查詢通過must(與)、must_not(非)、should(或)的方式進行組合

GET /heima/_search
{
    "query":{
        "bool":{
        	"must":     { "match": { "title": "大米" }},
        	"must_not": { "match": { "title":  "電視" }},
        	"should":   { "match": { "title": "手機" }}
        }
    }
}

結果:

{
  "took": 10,
  "timed_out": false,
  "_shards": {
    "total": 3,
    "successful": 3,
    "skipped": 0,
    "failed": 0
  },
  "hits": {
    "total": 1,
    "max_score": 0.5753642,
    "hits": [
      {
        "_index": "heima",
        "_type": "goods",
        "_id": "2",
        "_score": 0.5753642,
        "_source": {
          "title": "大米手機",
          "images": "http://image.leyou.com/12479122.jpg",
          "price": 2899
        }
      }
    ]
  }
}

3.3.2 範圍查詢(range)

range 查詢找出那些落在指定區間內的數字或者時間

GET /heima/_search
{
    "query":{
        "range": {
            "price": {
                "gte":  1000.0,
                "lt":   2800.00
            }
    	}
    }
}

range查詢允許以下字元:

操作符說明
gt大於
gte大於等於
lt小於
lte小於等於

3.3.3 模糊查詢(fuzzy)

我們新增一個商品:

POST /heima/goods/4
{
    "title":"apple手機",
    "images":"http://image.leyou.com/12479122.jpg",
    "price":6899.00
}

fuzzy 查詢是 term 查詢的模糊等價。它允許使用者搜尋詞條與實際詞條的拼寫出現偏差,但是偏差的編輯距離不得超過2:

GET /heima/_search
{
  "query": {
    "fuzzy": {
      "title": "appla"
    }
  }
}

上面的查詢,也能查詢到apple手機

我們可以通過fuzziness來指定允許的編輯距離:

GET /heima/_search
{
  "query": {
    "fuzzy": {
        "title": {
            "value":"appla",
            "fuzziness":1
        }
    }
  }
}

3.4 過濾(filter)

條件查詢中進行過濾

所有的查詢都會影響到文件的評分及排名。如果我們需要在查詢結果中進行過濾,並且不希望過濾條件影響評分,那麼就不要把過濾條件作為查詢條件來用。而是使用filter方式:

GET /heima/_search
{
    "query":{
        "bool":{
        	"must":{ "match": { "title": "小米手機" }},
        	"filter":{
                "range":{"price":{"gt":2000.00,"lt":3800.00}}
        	}
        }
    }
}

注意:filter中還可以再次進行bool組合條件過濾。

無查詢條件,直接過濾

如果一次查詢只有過濾,沒有查詢條件,不希望進行評分,我們可以使用constant_score取代只有 filter 語句的 bool 查詢。在效能上是完全相同的,但對於提高查詢簡潔性和清晰度有很大幫助。

GET /heima/_search
{
    "query":{
        "constant_score":   {
            "filter": {
            	 "range":{"price":{"gt":2000.00,"lt":3000.00}}
            }
        }
}

3.5 排序

3.4.1 單欄位排序

sort 可以讓我們按照不同的欄位進行排序,並且通過order指定排序的方式

GET /heima/_search
{
  "query": {
    "match": {
      "title": "小米手機"
    }
  },
  "sort": [
    {
      "price": {
        "order": "desc"
      }
    }
  ]
}

3.4.2 多欄位排序

假定我們想要結合使用 price和 _score(得分) 進行查詢,並且匹配的結果首先按照價格排序,然後按照相關性得分排序:

GET /goods/_search
{
    "query":{
        "bool":{
        	"must":{ "match": { "title": "小米手機" }},
        	"filter":{
                "range":{"price":{"gt":200000,"lt":300000}}
        	}
        }
    },
    "sort": [
      { "price": { "order": "desc" }},
      { "_score": { "order": "desc" }}
    ]
}

相關文章