ES 添加字段默认值

技术ES 添加字段默认值 ES 添加字段默认值ES 新增字段支持过滤
业务背景
当我们在使用多维度检索时,mysql显然已经不能满足我的的使用场景,尤其涉及到表之间的join且数据量较大时,mysql的

添加专家系统字段默认值

ES 新增字段支持过滤

业务背景

当我们使用多维检索时,mysql显然不能满足我的使用场景,尤其是涉及到表与表之间的连接,数据量大的时候,mysql的查询性能就捉襟见肘了。

这时,ES的多维检索功能就派上用场了。我们可以将两个或两个以上的业务表做成一个更宽的索引,监控业务的binlog,并将数据保存到es中。

这样可以快速支持业务检索。

业务需求

通常会用到ES的动态模板,以后添加其他维度过滤会更方便。

大家都知道文档存储在ES的底层。当使用POST将字段添加到动态模板中时,先前的数据将不会具有与mysql相同的默认值。

如果产品端需要支持旧数据的过滤,那么我们就要参与刷ES索引。

分析

按照数据组织的方式,将数据重新插入到ES中肯定是不可行的。那么我们有没有一个可以类似于mysql的设置默认值的命令呢?

所以我翻了翻ES的官方文档,看到更新可以支持这个操作。下面是一个在es动态索引中添加类型的示例,以演示解决过程。若要实现,请在es中添加类型=0的原始文档,并支持索引。

现有文档数

GET index _ test/_ count Pitty

{

计数' : 2000,

_碎片' : {

共计: 12,

成功' : 12,

跳过' : 0,

失败' : 0

}

}

你可以看到另外2000份文件,

使用ES的term查询:

实际上,“术语”是一个桶聚合查询,可以理解为mysql的group by。

POST _ index _ test/_ search Pitty

{

尺寸' : 0,

aggs' : {

aggType' : {

条款' : {

字段“:”类型

}

}

}

}

查询结果:

{

拍了' : 2,

' time out _ : false,

_碎片' : {

共计: 12,

成功' : 12,

跳过' : 0,

失败' : 0

},

点击量' : {

总计' : {

值' : 2000,

关系' : 'gte '

},

max_score' : null,

点击量' : [ ]

},

聚合' : {

aggType' : {

doc _ count _ error _ upper _ bound ' : 0,

sum_other_doc_count' : 0,

桶' : [

{

密钥' : 1,

doc_count' : 5

},

{

key' : 2,

doc_count' : 4

},

{

key' : 3,

doc_count' : 4

}

]

}

}

}

可以看到,没有type=0的数据,只有新生成的type=1、2、3、2、3的数据,分别是5、4、4,共13条,数据总条数为2000条。

有1987件物品不见了。这些数据都是旧数据,不支持该字段的检索。

使用update更新

POST索引_test/_update/1

{

脚本' : {

lang': '无痛',

来源' : '

if (ctx。_source.type==null) { ctx。_source.type=0 }

'''

}

}

ES update支持脚本,这样我们在加载更新文档的时候,就可以根据其他一个或者几个字段来确认新添加的字段的值,我这里用的就是这个。

如果type为空,则将type指定为默认值0。

更新后使用术语查询结果。

` `` json

{

拍了' : 2,

time out _ : false,

_碎片' : {

共计: 12,

成功f

ul" : 12,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : {
"value" : 2000,
"relation" : "gte"
},
"max_score" : null,
"hits" : [ ]
},
"aggregations" : {
"aggType" : {
"doc_count_error_upper_bound" : 0,
"sum_other_doc_count" : 0,
"buckets" : [
{
"key" : 0,
"doc_count" : 1
}
{
"key" : 1,
"doc_count" : 5
},
{
"key" : 2,
"doc_count" : 4
},
{
"key" : 3,
"doc_count" : 4
}
]
}
}
}

发现只增加了一条,重复执行更新命令也不会再增加了,通过分析update语句发现,其命令行update后的1指的是doc
Id。这种方式显然不能使用,我再猜想有没有类似mysql中根据条件update的语句呀查看官方文档后,返现ES支持
update_by_query的操作

使用update_by_query

使用update_by_query语句,在这里我删除了script中的条件判断,改成使用query

POST index_test/_update_by_query
{
    "script": {
        "lang": "painless",
        "source": "ctx._source.type=0"
    },
    "query": {
        "bool": {
            "must_not": {
                "exists": {
                    "field": "type"
                }
            }
        }
    }
}

其实使用scrpit的脚本判断要比query中使用must_not要慢。我理解使用script要access all 全表扫描。
如果使用了must_not 而且只有一个条件,我理解ES的执行引擎会使用倒排所以,查询出有的,然后取反,把不存在该字段的
doc ID返回。根据id去逐条更新,这样判断的次数从O(n)降到了理论的O(1)。

待结果返回后,重新使用term查询结果:

POST index_test/_searchpretty
{
    "size" : 0,
    "aggs" : {
        "aggType" : {
            "terms" : {
                "field" : "type"
            }
        }
    }
}

查询结果:

{
  "took" : 2,
  "timed_out" : false,
  "_shards" : {
    "total" : 12,
    "successful" : 12,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 2000,
      "relation" : "gte"
    },
    "max_score" : null,
    "hits" : [ ]
  },
  "aggregations" : {
    "aggType" : {
      "doc_count_error_upper_bound" : 0,
      "sum_other_doc_count" : 0,
      "buckets" : [
          {
          "key" : 0,
          "doc_count" : 1987
        }
        {
          "key" : 1,
          "doc_count" : 5
        },
        {
          "key" : 2,
          "doc_count" : 4
        },
        {
          "key" : 3,
          "doc_count" : 4
        }
      ]
    }
  }
}

可以看到聚合结果中key=0的文档相较之前增加了好多,而且key = 0,1,2,3,4 的枚举加起来正好为2000.
证明更新成功了。

控制更新速度

在更新的过程中,如果要控制更新的速度,可以在更新的语句后添加参数,目前ES更新支持两个方式

按照索引分片更新

POST index_test/_update_by_queryrouting=1

其中routing为集群的第几个分片。

  • 优点:单分片更新,如果分片被更新坏了,可以找运维删除分片,副本分片会主动替换主分片,并重新
    分片副本分片,在这期间索引的状态可能是黄色。
  • 缺点:更新不是原子的,而且需要清楚集群有多少个主分片才可以操作。

按照分页更新

POST index_test/_update_by_queryscroll_size=10000

其中scroll_size的最大值为集群配置的允许的最大值,可以通过_settings命令查询。

  • 优点:可以控制集群中数据的更新速度,降低修复数据时,集群的负载。
  • 缺点:需要判断使用合理的分页,一旦集群崩溃就会影响线上环境。

触类旁通

ES集群使用的SSD的硬盘,而且对内存要求较高,
当集群的存储超过一半时(超过了一半ES就无法再实现段合并了,高并发写入会产生较多分段Segment)
。一半情况下,业务的数据都是按照日期存储的,这时候我们可以把较早的数据备份到HDFS系统上,然后
在ES的集群上执行delete_by_query可以删除部分历史数据,这样可以使得ES集群一直处于比较好的性能区间。

I am chris, not arax!

内容来源网络,如有侵权,联系删除,本文地址:https://www.230890.com/zhan/112083.html

(0)

相关推荐