【Elastic Engineering】Elasticsearch:使用 alias 数据类型来遵循 ECS (Elastic Common Schema)

本文涉及的产品
检索分析服务 Elasticsearch 版,2核4GB开发者规格 1个月
简介: Elasticsearch:使用 alias 数据类型来遵循 ECS (Elastic Common Schema)

作者:刘晓国


在很多的设计中,我们所采集的数据来自不同的数据源,从而导致数据字段名称的不一致。如果,我们在一开始就遵循 Elastic Common Schema,那么我们就不会有任何的问题。但是在实际的生产环境中,有可能在一开始我们就没有这么做,那我们该如何解决这个问题呢?比如我们有如下的两个数据:

POST logs_server1/_doc/
{
  "level": "info"
}
POST logs_server2/_doc/
{
  "log_level": "info"
}

在上面的两个数据是来自两个不同的服务器,在当时设计的时候,表示 log 的级别分别用了不同的字段:level 及 log_level。显然这两个不同的字段不便于我们统计数据。安装 Elastic Common Schema image.png的要求,正确的字段应该是 log.level。那么我们在不改变原有的 log 的设计基础之上,该如何实现符号 ECS 规范的 mapping 呢?


在之前的文章 “Elasticsearch : alias 数据类型”,我已经讲述了 alias 的数据类型。在今天的文章中,我来详细描述如何使用 alias 来解决这个问题。


准备数据

我们安装上面所显示的那样,把两个数据导入到 Elasticsearchimage.png中:

POST logs_server1/_doc/
{
  "level": "info"
}
POST logs_server2/_doc/
{
  "log_level": "info"
}

我们可以通过如下的命令来检查一下这两个索引的 mapping:

GET logs_server1/_mapping
{
  "logs_server2" : {
    "mappings" : {
      "properties" : {
        "log_level" : {
          "type" : "text",
          "fields" : {
            "keyword" : {
              "type" : "keyword",
              "ignore_above" : 256
            }
          }
        }
      }
    }
  }
}

显然上面的两个索引的 mapping 都是不一样的。


如果我们想统计一下 logs 按照级别 level 进行统计的话,我们只能按照如下的方法来进行:

GET logs_server*/_search
{
  "size": 0,
  "aggs": {
    "levels": {
      "terms": {
        "script": {
          "source": """
             if (doc.containsKey('level.keyword')) {
               return doc['level.keyword'].value
             } else {
               return doc['log_level.keyword'].value
             }
          """
        }
      }
    }
  }
}

在上面,我使用了 script 来进行统计。在上面脚本中的 doc,其实就是 doc_values。如果大家对这个 doc 的方法不是很熟悉的话,请参阅我之前的文章 “Elasticsearch:Painless 编程调试”。我们可以使用如下的方法:

GET logs_server*/_search
{
  "size": 0,
  "aggs": {
    "levels": {
      "terms": {
        "script": {
          "source": """
            Debug.explain(doc)
          """
        }
      }
    }
  }
}

上面的查询会导致如下的错误信息:

{
  "error" : {
    "root_cause" : [
      {
        "type" : "script_exception",
        "reason" : "runtime error",
        "to_string" : "org.elasticsearch.search.lookup.LeafDocLookup@6814c133",
        "java_class" : "org.elasticsearch.search.lookup.LeafDocLookup",
        "script_stack" : [
          "Debug.explain(doc)\n          ",
          "              ^---- HERE"
        ],
        "script" : "\n            Debug.explain(doc)\n          ",
        "lang" : "painless",
        "position" : {
          "offset" : 27,
          "start" : 13,
          "end" : 42
        }
      },
      {
        "type" : "script_exception",
        "reason" : "runtime error",
        "to_string" : "org.elasticsearch.search.lookup.LeafDocLookup@6454e4d",
        "java_class" : "org.elasticsearch.search.lookup.LeafDocLookup",
        "script_stack" : [
          "Debug.explain(doc)\n          ",
          "              ^---- HERE"
        ],
        "script" : "\n            Debug.explain(doc)\n          ",
        "lang" : "painless",
        "position" : {
          "offset" : 27,
          "start" : 13,
          "end" : 42
        }
      }
    ],
    "type" : "search_phase_execution_exception",
    "reason" : "all shards failed",
    "phase" : "query",
    "grouped" : true,
    "failed_shards" : [
      {
        "shard" : 0,
        "index" : "logs_server1",
        "node" : "2bFyWe-OSpeW98xsZMrjng",
        "reason" : {
          "type" : "script_exception",
          "reason" : "runtime error",
          "to_string" : "org.elasticsearch.search.lookup.LeafDocLookup@6814c133",
          "java_class" : "org.elasticsearch.search.lookup.LeafDocLookup",
          "script_stack" : [
            "Debug.explain(doc)\n          ",
            "              ^---- HERE"
          ],
          "script" : "\n            Debug.explain(doc)\n          ",
          "lang" : "painless",
          "position" : {
            "offset" : 27,
            "start" : 13,
            "end" : 42
          },
          "caused_by" : {
            "type" : "painless_explain_error",
            "reason" : null
          }
        }
      },
      {
        "shard" : 0,
        "index" : "logs_server2",
        "node" : "2bFyWe-OSpeW98xsZMrjng",
        "reason" : {
          "type" : "script_exception",
          "reason" : "runtime error",
          "to_string" : "org.elasticsearch.search.lookup.LeafDocLookup@6454e4d",
          "java_class" : "org.elasticsearch.search.lookup.LeafDocLookup",
          "script_stack" : [
            "Debug.explain(doc)\n          ",
            "              ^---- HERE"
          ],
          "script" : "\n            Debug.explain(doc)\n          ",
          "lang" : "painless",
          "position" : {
            "offset" : 27,
            "start" : 13,
            "end" : 42
          },
          "caused_by" : {
            "type" : "painless_explain_error",
            "reason" : null
          }
        }
      }
    ]
  },
  "status" : 400
}

从上面我们可以看出来 doc 是一个 org.elasticsearch.search.lookup.LeafDocLookup 类型的数据。我们可以通过谷歌搜索来找到这个数据类型的所有方法。其中 containsKey 的描述在链接 https://www.javadoc.io/doc/org.elasticsearch/elasticsearch/6.0.1/org/elasticsearch/search/lookup/LeafDocLookup.html


上面按照脚本的方法来进行统计,有一个很大的缺点:每次在统计的时候都需要进行计算,如果有大量的数据的话,这样的计算量会很大。那么有没有一种比较简单的方法呢?


使用 alias 数据类型把数据归一化


我们参照之前的文章 “Elasticsearch : alias 数据类型”,我们可以把 level 都按照 ECS 的要求,对应于 log.level。对上面的两个索引做如下的操作:

PUT logs_server1/_mapping
{
  "properties": {
    "log": {
      "properties": {
        "level": {
          "type": "alias",
          "path": "level.keyword"
        }
      }
    }
  }
}

经过上面的操作后,logs_sever1 的 mapping 如下:

GET logs_server1/_mapping
{
  "logs_server1" : {
    "mappings" : {
      "properties" : {
        "level" : {
          "type" : "text",
          "fields" : {
            "keyword" : {
              "type" : "keyword",
              "ignore_above" : 256
            }
          }
        },
        "log" : {
          "properties" : {
            "level" : {
              "type" : "alias",
              "path" : "level.keyword"
            }
          }
        }
      }
    }
  }
}

同样地,我们对 logs_server2 也进行同样的操作:

PUT logs_server2/_mapping
{
  "properties": {
    "log": {
      "properties": {
        "level": {
          "type": "alias",
          "path": "log_level.keyword"
        }
      }
    }
  }
}

那么 logs_server2 的 mapping 变为:

{
  "logs_server2" : {
    "mappings" : {
      "properties" : {
        "log" : {
          "properties" : {
            "level" : {
              "type" : "alias",
              "path" : "log_level.keyword"
            }
          }
        },
        "log_level" : {
          "type" : "text",
          "fields" : {
            "keyword" : {
              "type" : "keyword",
              "ignore_above" : 256
            }
          }
        }
      }
    }
  }
}

经过上面的改造之后,我们可以看出来,这两个索引的 mapping 都有一个共同的字段 log.level,尽管它们是 alias 数据类型。


我们很容易使用如下的方法来对 level 进行统计了:

GET  logs_server*/_search
{
  "size": 0,
  "aggs": {
    "levels": {
      "terms": {
        "field": "log.level",
        "size": 10
      }
    }
  }
}

现在显然比之前的 script 来统计数据方便很多了,而且它不需要有大量的计算了。


相关实践学习
使用阿里云Elasticsearch体验信息检索加速
通过创建登录阿里云Elasticsearch集群,使用DataWorks将MySQL数据同步至Elasticsearch,体验多条件检索效果,简单展示数据同步和信息检索加速的过程和操作。
ElasticSearch 入门精讲
ElasticSearch是一个开源的、基于Lucene的、分布式、高扩展、高实时的搜索与数据分析引擎。根据DB-Engines的排名显示,Elasticsearch是最受欢迎的企业搜索引擎,其次是Apache Solr(也是基于Lucene)。 ElasticSearch的实现原理主要分为以下几个步骤: 用户将数据提交到Elastic Search 数据库中 通过分词控制器去将对应的语句分词,将其权重和分词结果一并存入数据 当用户搜索数据时候,再根据权重将结果排名、打分 将返回结果呈现给用户 Elasticsearch可以用于搜索各种文档。它提供可扩展的搜索,具有接近实时的搜索,并支持多租户。
相关文章
|
4月前
|
自然语言处理 关系型数据库 数据库
ElasticSearch 映射类型及数据类型区分
ElasticSearch 映射类型及数据类型区分
53 0
|
1月前
|
SQL 分布式计算 NoSQL
大数据-170 Elasticsearch 云服务器三节点集群搭建 测试运行
大数据-170 Elasticsearch 云服务器三节点集群搭建 测试运行
41 4
|
1月前
|
SQL 分布式计算 大数据
大数据-168 Elasticsearch 单机云服务器部署运行 详细流程
大数据-168 Elasticsearch 单机云服务器部署运行 详细流程
56 2
|
6月前
|
测试技术 定位技术 API
万字长文:一文彻底搞懂Elasticsearch中Geo数据类型查询、聚合、排序
万字长文:一文彻底搞懂Elasticsearch中Geo数据类型查询、聚合、排序
95134 140
|
6月前
|
运维 架构师 搜索推荐
7 年+积累、 Elastic 创始人Shay Banon 等 15 位专家推荐的 Elasticsearch 8.X新书已上线...
7 年+积累、 Elastic 创始人Shay Banon 等 15 位专家推荐的 Elasticsearch 8.X新书已上线...
84 4
|
6月前
|
存储 安全 数据处理
Elastic 中国开发者大会2023最新干货——Elasticsearch 7、8 新功能一网打尽
Elastic 中国开发者大会2023最新干货——Elasticsearch 7、8 新功能一网打尽
69 0
|
6月前
|
存储 安全 网络协议
云服务器 Centos7 部署 Elasticsearch 8.0 + Kibana 8.0 指南
云服务器 Centos7 部署 Elasticsearch 8.0 + Kibana 8.0 指南
352 0
|
6月前
|
弹性计算 安全 Ubuntu
ECS(Elastic Compute Service)中选择镜像
ECS(Elastic Compute Service)中选择镜像
114 4
|
6月前
|
弹性计算 容灾 定位技术
ECS(Elastic Compute Service)地域和可用区的选择
ECS(Elastic Compute Service)地域和可用区的选择
175 2
|
11月前
|
搜索推荐 索引
Elasticsearch elastic io 100%,但磁盘的iops和吞吐量没爆没啥原因吗?
Elasticsearch elastic io 100%,但磁盘的iops和吞吐量没爆没啥原因吗?
182 3

相关产品

  • 检索分析服务 Elasticsearch版
  • 下一篇
    无影云桌面