Elastic學習之旅 (9) 結構化搜索

大家好,我是Edison。

上一篇:基於Term和全文的ES查詢

結構化數據

結構化搜索(Structured Search)是指對結構化數據的搜索,那麼,什麼數據是結構化的呢?

ES中日期、布爾類型和數字都是結構化的。

另外,文本也可以是結構化的:

  • 比如彩色筆可以有離散的顏色集合:紅、藍、綠等;

  • 一個博客也可能被標記了一些標籤:分佈式、搜索、架構等;

  • 電商網站上的商品都有UPCs(通用產品碼)或其他的唯一標識,它們都需要遵從嚴格規定的、結構化的格式。

結構化搜索

結構化搜索(Structured Search)是指對結構化數據的搜索,那麼我們接下來就看看如何做結構化搜索。在ES中對結構化數據進行匹配,主要使用term查詢。

NOTE:對於文本的全文查詢,主要使用match喲。

首先,我們先添加一些測試數據,以便後續場景中的示例。請注意裏面這些測試數據的結構,後面兩條並沒有date字段喲。

DELETE products
POST /products/_bulk
{ "index":{"_id":1}}
{ "productID": "XHDK-A-1293-#fJ3", "price":10, "avaliable":true, "date":"2024-04-01"}
{ "index":{"_id":2}}
{ "productID": "KDKE-B-9947-#kL5", "price":20, "avaliable":true, "date":"2023-04-01"}
{ "index":{"_id":3}}
{ "productID": "J0DL-X-1937-#pV7", "price":30, "avaliable":true }
{ "index":{"_id":4}}
{ "productID": "QQPX-R-3956-#aD8", "price":30, "avaliable":false }

場景1:針對布爾、時間、日期和數字類型的結構化數據

這類數據有精確的格式,可以直接對這些格式進行邏輯操作,比如 比較數字或時間的範圍,或判定兩個值的大小。

(1)布爾值

// 對布爾值進行查詢(有算分)
// ES會返回3條記錄
POST /products/_search
{
  "profile": "true",
  "query": {
    "term": {
      "avaliable": true
    }
  }
}

ES返回結果:3條記錄,有計算分

從之前的學習中,我們知道,可以使用constant_score轉成filtering,進而避免算分,提高性能。

// 對布爾值進行查詢(使用constant_score,無算分)
// ES會返回3條記錄
POST /products/_search
{
  "profile": "true",
  "query": {
    "constant_score": {
      "filter": {
        "term": {
          "avaliable": true
        }
      }
    }
  }
}

ES返回結果:3條記錄,沒有計算分

(2)數字和日期Range

// 數字Range查詢價格>=30 並 <=40的記錄
POST /products/_search
{
  "profile": "true",
  "query": {
    "constant_score": {
      "filter": {
        "range": {
          "price": {
            "gte": 30,
            "lte": 40
          }
        }
      }
    }
  }
}

// 日期Range查詢:查詢近一年的記錄
// y 年 M 月 w 周 d 天 
// H / h 小時 m 分鐘 s 秒
POST /products/_search
{
  "profile": "true",
  "query": {
    "constant_score": {
      "filter": {
        "range": {
          "date": {
            "gte": "now-1y"
          }
        }
      }
    }
  }
}

(3)處理空值

// exists 可以過濾不包含某字段的記錄
POST /products/_search
{
  "profile": "true",
  "query": {
    "constant_score": {
      "filter": {
        "exists": {
          "field": "date"
        }
      }
    }
  }
}

場景2:針對結構化文本做部分匹配 或 精確匹配

爲了演示,我們插入兩個測試數據來看看處理多值的情況:

POST /movies/_bulk
{ "index":{"_id":1}}
{ "title": "Father of the Bridge Part II", "year": 1995, "genre": "Comedy" }
{ "index":{"_id":2}}
{ "title": "Dave", "year": 1993, "genre": ["Comedy", "Romance"] }

可以看到,第二條數據的genre字段包含了多個值,是一個集合字段。

然後,我們可以通過term+ keyword來處理多值字段的查詢:查找genre屬於Comedy(喜劇)的記錄。這裏需要注意的是,term查詢的邏輯關係是包含而不是完全相等,所以它做的是部分匹配

// 查詢包含單個值的記錄
POST /movies/_search
{
  "query": {
    "constant_score": {
      "filter": {
        "term": {
          "genre.keyword": "Comedy"
        }
      }
    }
  }
}

// 查詢包含多個值的記錄
POST /movies/_search
{
  "query": {
    "constant_score": {
      "filter": {
        "terms": {
          "genre.keyword": [
            "Comedy",
            "Romance"
          ]
        }
      }
    }
  }
}

這裏如果我們想做精確匹配,我們可以增加一個count字段並使用bool查詢來解決。

Step1.從業務角度,按需改進ES的數據模型

POST /movies_new/_bulk
{ "index":{"_id":1}}
{ "title": "Father of the Bridge Part II", "year": 1995, "genre": "Comedy", "genre_count":1 }
{ "index":{"_id":2}}
{ "title": "Dave", "year": 1993, "genre": ["Comedy", "Romance"], "genre_count":2 }

這裏可以看到,我們給genre字段新增一個匹配的genre_count字段,代表genre字段有幾個值。

Step2.使用bool查詢進行精確匹配

// 方式一:使用must,有算分
POST /movies_new/_search
{
  "query": {
    "bool": {
      "must": [
        {"term":{"genre.keyword": {"value":"Comedy"}}},
        {"term":{"genre_count": {"value":1}}}
      ]
    }
  }
}
// 方式二:使用filter,無算分
POST /movies_new/_search
{
  "query": {
    "bool": {
      "filter": [
        {"term":{"genre.keyword": {"value":"Comedy"}}},
        {"term":{"genre_count": {"value":1}}}
      ]
    }
  }
}

小結

本篇,我們瞭解了ElasticSearch中的結構化數據和結構化搜索的概念,並通過幾個實例瞭解瞭如何對結構化數據進行搜索。在ES中,我們主要使用term對結構化數據進行搜索,而主要使用match對文本進行全文搜索。

參考資料

極客時間,阮一鳴,《ElasticSearch核心技術與實戰

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章