Elasticsearch 7.x Nested 嵌套類型查詢 | ES 乾貨

1、什麼是 ES Nested 嵌套

Elasticsearch 有不少數據類型,大體以下:html

  • 基本數據類型:
    • string 類型。ES 7.x 中,string 類型會升級爲:text 和 keyword。keyword 能夠排序;text 默認分詞,不能夠排序。
    • 數據類型:integer、long 等
    • 時間類型、布爾類型、二進制類型、區間類型等
  • 複雜數據類型:
    • 數組類型:Array
    • 對象類型:Object
    • Nested 類型
  • 特定數據類型:地理位置、IP 等

注意:tring/nested/array 類型字段不能用做排序字段。所以 string 類型會升級爲:text 和 keyword。keyword 能夠排序,text 默認分詞,不能夠排序。java

file

2.1 那什麼是 Nested 類型?

Elasticsearch 7.x 文檔中,這樣寫到:json

The nested type is a specialised version of the object datatype that allows arrays of objects to be indexed in a way that they can be queried independently of each other.

Nested (嵌套)類型,是特殊的對象類型,特殊的地方是索引對象數組方式不一樣,容許數組中的對象各自地進行索引。目的是對象之間彼此獨立被查詢出來。數組

2.2 如何使用 Nested 類型?

在 ES 的 my_index 索引中存儲 users 字段。好比說:性能優化

{
  "group" : "fans",
  "users" : [
    {
      "name" : "John",
      "age" :  "23"
    },
    {
      "name" : "Alice",
      "age" :  "18"
    }
  ]
}

其實存儲看上去跟 Object 類型同樣,只不過底層原理對數組 users 字段索引方式不一樣。設置 users 字段的索引方式 Nested 嵌套類型:網絡

curl -X PUT "localhost:9200/my_index" -H 'Content-Type: application/json' -d'
{
  "mappings": {
    "properties": {
      "users": {
        "type": "nested" 
      }
    }
  }
}
'

2、Nested Query 應用場景或案例

好比小老弟我有一波小粉絲,users 字段類型是 object。存儲以下:併發

{
  "group" : "bysocket_fans",
  "users" : [
    {
      "name" : "John",
      "age" :  "23"
    },
    {
      "name" : "Alice",
      "age" :  "18"
    }
  ]
}

{
  "group" : "路人甲_fans",
  "users" : [
    {
      "name" : "Alice",
      "age" :  "22"
    },
    {
      "name" : "Jeff",
      "age" :  "18"
    }
  ]
}

好比 18 歲大姑娘 Alice 是小老弟個人粉絲,她也多是周杰倫的粉絲。那這邊就有一個需求,即應用場景:app

如何找到 18 歲大姑娘 Alice {"name" : "Alice","age" :  "18"} 關注的全部明星呢?curl

若是用老的查詢語句是這樣搜索的:socket

GET /my_index/_search?pretty
{
  "query": {
    "bool": {
      "must": [
        {
          "match": {
            "users.name": "Alice"
          }
        },
        {
          "match": {
            "users.age": 18
          }
        }
      ]
    }
  }
}

結果發現結果是不對的,路人甲 這條記錄也出現了。 由於匹配到了第一個 Alice + 第二個 Jeff 的 18。因此這種查詢不知足這個場景

那麼須要使用 Nested 類型並用 Nested 查詢,即讓數組中的對象各自地進行索引。目的是對象之間彼此獨立被查詢出來。

3、Nested Query 實戰

3.1 設置 Nested 類型

根據 2.2 如何使用 Nested 類型,將 users 字段類型從 object 修改成 nested:

curl -X PUT "localhost:9200/my_index" -H 'Content-Type: application/json' -d'
{
  "mappings": {
    "properties": {
      "users": {
        "type": "nested" 
      }
    }
  }
}
'

3.2 Nested Query

修改後,對應的 Nested Query ,以下:

GET /my_index/_search?pretty
{
  "query": {
    "bool": {
      "must": [
        {
          "nested": {
            "path": "users",
            "query": {
              "bool": {
                "must": [
                  {
                    "match": {
                      "users.name": "Alice"
                    }
                  },
                  {
                    "match": {
                      "users.age": 18
                    }
                  }
                ]
              }
            }
          }
        }
      ]
    }
  }
}

語法很簡單就是:

  • key 以 "nested" 開頭
  • path 就是嵌套對象數組的字段名
  • 其餘
    • score_mode (可選的)匹配子對象的分數相關性分數。avg (默認,使用全部匹配子對象的平均相關性分數)
    • ignore_unmapped (可選的)是否忽略 path 未映射,不返回任何文檔而不是錯誤。默認爲 false,若是 path 不對就報錯

這樣查詢得結果就是對的。

4、Nested Query 性能

這邊測試過,給你們一個測試報告和建議。

file

壓測環境:3 個 server ,6 個 ES 節點

壓測結論: 使用上小節查詢語句,50 併發狀況下,致使千兆網卡被打滿了。TPS 4000 左右,若是提升併發,就會增長 RT。因此若是高性能大流量狀況下,必須用 Nested 應該從網絡流量方向進行優化。兩者,儘可能減小大數據對象的返回

建議:泥瓦匠建議,你聽聽看

  • 性能:Common Query 遠遠大於 Nested Query 遠遠大於 Parent/Child Query
  • 性能優化:首先考慮減小後面兩種 Query
  • 性能優化:Nested Query 業務能夠優化下。好比上一小節徹底能夠多存一個 fanIds 數組。搜索兩次,第一次查肯定 18 歲大姑娘 Alice 的 fanId,第二次根據 fanId 搜索便可
  • 性能優化:實在沒辦法,高性能大流量狀況下,必須用 Nested 應該從網絡流量方向進行優化。兩者,儘可能減小大數據對象的返回

(完)

參考資料:

相關文章
相關標籤/搜索