巧用es flattened

2023-01-08  本文已影响0人  郭彦超

好久没更新了 今天讲下如何借助ES的flatten数据类型解决字段膨胀的问题

背景介绍

目前商城业务中需要使用ES完成一项特殊的排序逻辑:任意一件商品可以被运营划分到多个品类下,当遇到节假日或者热点时,运营同学需要干预商品排序,即在某些品类下的商品可以按照特定字段值进行排序,没有设置运营排序值的则需要按照综合分进行排序

问题描述

我们知道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 必须为每个新字段更新集群状态,并且该集群状态必须传递给所有节点。跨节点的集群状态传输是单线程操作 , 因此要更新的字段映射越多,完成更新所需的时间就越长。这种延迟通常以性能不佳的集群而结束,有时会导致整个集群停机。这被称为 “映射爆炸(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、失去了使用不区分大小写的查询的能力,这样你就不必输入完全匹配的查询
2、排序仅支持按照字符大小进行排序

上一篇下一篇

猜你喜欢

热点阅读