巧用es flattened

好久沒更新了 今天講下如何借助ES的flatten數據類型解決字段膨脹的問題

背景介紹

目前商城業(yè)務中需要使用ES完成一項特殊的排序邏輯:任意一件商品可以被運營劃分到多個品類下,當遇到節(jié)假日或者熱點時,運營同學需要干預商品排序,即在某些品類下的商品可以按照特定字段值進行排序,沒有設置運營排序值的則需要按照綜合分進行排序

問題描述

我們知道ES并不擅長做數據關聯,那么如何實現一件商品可以按照不同的品類權重值進行排序呢?

解決思路

這里想到的是借助ES的嵌套結構來實現,即每一個嵌套子文檔都是一個k/v結構,key為品類id,value為排序值,如下:

 "navigator_sort" : {
            "895729" : 0,
            "895839" : 0 ,
            "895567" : 100,
            "898804" : 0,
            "898805" : 0,
            "895566" : 75 
 }

如果需要按照指定的品類進行排序,那么可以這么做:

  "sort": [
    {
      "navigator_sort.895567": {
        "order": "desc"
      }
    }
  ]

面臨的問題

默認情況下,Elasticsearch 會在提取nested字段中內容時,會自動映射文檔中包含的字段。 雖然這是使用 Elasticsearch 的最簡單方法,但隨著時間的推移,它往往會導致字段爆炸,并且 Elasticsearch 的性能將受到 “內存不足(out of memory)” 錯誤以及索引和查詢數據時性能不佳的影響。

什么是字段爆炸?
Elasticsearch 必須為每個新字段更新集群狀態(tài),并且該集群狀態(tài)必須傳遞給所有節(jié)點。跨節(jié)點的集群狀態(tài)傳輸是單線程操作 , 因此要更新的字段映射越多,完成更新所需的時間就越長。這種延遲通常以性能不佳的集群而結束,有時會導致整個集群停機。這被稱為 “映射爆炸(mapping explosion)”。
這也是 Elasticsearch 從 5.x 及更高版本開始將索引中的字段數限制為 1,000 個的原因之一。如果我們的字段數超過 1,000,我們必須手動更改默認索引字段限制(使用 index.mapping.total_fields.limit 設置)或者我們需要重新考慮我們的架構。

替代方案 flattened

使用 Elasticsearch Flattened數據類型,具有大量嵌套字段的對象被視為單個關鍵字字段。 換句話說,Elasticsearch 扁平化數據類型用于有效減少Mapping中包含的字段數量,同時仍允許我們查詢扁平化數據

# 構建索引
PUT my-index-000001
{
  "mappings": {
    "properties": {
      "title": {
        "type": "text"
      },
      "create_user": {
        "type": "keyword"
      },
      "full_path_json": {
        "type": "flattened",
        "similarity": "boolean"
      }
    }
  }
}

# 保存一條這樣的數據
    {
          "title" : "Something really urgent",
          "create_user" : "1",
          "full_path_json" : [
            {
              "op_user" : "A",
              "folders" : [
                "v3",
                "v4",
                "v3tv4"
              ],
              "A" : {
                "op_time" : "2022-01-12",
                "is_share" : 1,
                "in_folder" : 1
              }
            },
            {
              "op_user" : "2",
              "2" : {
                "op_time" : "2022-12-12",
                "is_share" : 1
              }
            }
          ]
     }

# 查詢和排序
GET my-index-000001/_search
{
   "sort": [
     {
       "full_path_json.A.op_time": {
         "order": "desc"
       }
     }
   ], 
  "query": {
    "bool": {
      "filter": [
        {
          "term": {
            "title": "urgent"
          }
        },
        {
          "term": {
            "full_path_json.folders": "f3"
          }
        } 
      ]
    }
  }
}

雖然可以查詢在單個字段中 “扁平化” 的嵌套字段,但需要注意某些限制。 扁平對象中的所有字段值都存儲為keyword 【 keyword類型字段不進行任何類型的文本分詞(text tokenization)或分析,而是按原樣存儲】
失去的特性:
1、失去了使用不區(qū)分大小寫的查詢的能力,這樣你就不必輸入完全匹配的查詢
2、排序僅支持按照字符大小進行排序

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

友情鏈接更多精彩內容