1、基本概念
1.1version
_version是es索引的一个隐藏字段,创建索引时自动生成,且初始值为1,它顾名思义就是一个版本号,当索引发生改动的时候会自动加1;想查看它的值,需要在搜索时加上version=true
举例:
建立一个只有一个字段的索引并填充几条数据
DELETE news_00001
PUT news_00001
{
"mappings": {
"properties": {
"tetttttt": {
"type": "integer"
}
}
}
}
POST news_00001/_bulk
{"index":{"_id":1}}
{"tetttttt":500}
{"index":{"_id":2}}
{"tetttttt":100}
{"index":{"_id":3}}
{"tetttttt":900}
{"index":{"_id":4}}
{"tetttttt":600}
查看它的version
GET /news_00001/_search?version=true
修改后再看version
PUT /news_00001/_doc/1
{
"tetttttt":108
}
GET /news_00001/_search?version=true
1.2runtime fields(7.11后的新特性)
runtime fields叫运行时字段,想了解它不如先看个场景;
同样以上面1.1创建的索引为例;如下命令就是给索引添加了一个runtime fields,叫做isUpdate:他的意思呢就是判断这个索引是否被修改过,是的话赋值为1,没有的话是0
PUT news_00001/_mapping
{
"runtime": {
"isUpdate": {
"type": "keyword",
"script": {
"source": "if (doc['_version'].value < 2 ) emit('0'); if (doc['_version'].value >= 2) emit('1');"
}
}
}
}
普通查询,发现没有isUpdate这个字段
GET news_00001/_search?version=true
{
"query": {
"match": {
"isUpdate": "1"
}
}
}
runtime fields想要被查到,需要类似如下命令
GET news_00001/_search?version=true
{
"fields": [
"*"
],
"query": {
"match": {
"isUpdate": "1"
}
}
}
以上两步可以一步实现,查询时建立映射关系
GET news_00001/_search?version=true
{
"runtime_mappings": {
"isUpdate": {
"type": "keyword",
"script": {
"source": "if (doc['_version'].value < 2 ) emit('0'); if (doc['_version'].value >= 2) emit('1');"
}
}
},
"fields": [
"*"
],
"query": {
"match": {
"isUpdate": "1"
}
}
}
至此我们是不是已经感受到runtime fields的妙处了,它十分方便的帮助已创建的索引添加字段;而且它还能随时修改字段类型,这在7.11版本之前对于es来说一直是个麻烦的问题,涉及到字段类型的修改就要重新创建索引,迁移数据,删除老索引这一套操作。,此外它同样能够作为普通字段一样去查询,去做聚合。
优点:
非常灵活,需要时用,不需要时随时可以删除。
可以先创建索引,填入数据再去定义字段,它并不占用存储。
缺点:
万事都有两面性,获得空间的代价就是牺牲了时间,它每次查询时这里面的映射关系是查询时额外计算处理的,这就影响了性能。
2.方案介绍
我们在看完上面对_version的介绍就能理解到为什么我想用它来做数据防篡改,我通过定时监控_version的变化,及时发现数据已被修改。
但是碰到一个问题就是,_version不能作为查询条件去搜索,这就意味着我需要把数据库所有数据都遍历一遍去判断_version是否改变,当数据量庞大的时候那肯定是极度低效的;
紧接着runtime fields不就用上了嘛,哈哈建一个新的runtime field,与_version建立映射关系,每次我搜索的时候直接把runtime field作为查询条件即可!