文档章节

Elasticsearch 同一索引不同类型下同名字段的映射冲突实例

MrYx3en
 MrYx3en
发布于 2015/11/16 19:55
字数 1063
阅读 262
收藏 3

    这个标题肯定绕晕很多人吧。具体说明一下场景就明白了:Nginx 和 Apache 的访问日志,因为都属于网站访问,所以写入到同一个索引的不同类型下,比方 logstash-accesslog-2015.04.03/nginx 和 logstash-accesslog-2015.04.03/apache。既然都是访问日志,肯定很多字段的内容含义是雷同的,比如 clientip, domain, urlpath 等等。其中 nginx 有一个变量叫 $request_time,apache 有一个变量叫 %T,乍看上去也是同义的,我就统一命名为 “requestTime” 了。这就是”同一索引(logstash-accesslog-YYYY.MM.DD)下不同类型(nginx,apache)的同名字段(requestTime)”。

但事实上,这里有个问题:nginx 中的以秒为单位,是把毫秒算作小数;apache 中的以秒为单位,是真的只记秒钟整数位!

所以,这两个类型生成的映射在这个字段上是不一致的。nginx 类型的 requestTime 是 double,apache 类型的 requestTime 是 long

不过平常看起来似乎也没什么影响,写入数据都照常,查看数据的时候默认显示的 JSON 也各自无异。直到我准备用一把 scripted field 的时候,发现计算 doc['requestTime'].value * 1000 得到的数都大的吓人!

因为类似计算之前在只有 nginx 日志入库的时候曾经正确运行过,所以只能是猜测 apache 日志对此造成了影响,但是即使我把请求修改成限定在 nginx 类型数据中进行,结果也没发生变化。

仔细阅读 scripting module 的文档,其中提到了 doc['fieldname'].value 和_source.fieldname 两种写法的区别:前者会利用内存中的数据,而后者强制读取磁盘上_source 存储的 JSON 内容,从中释放出相应字段内容。莫非是 requestTime 字段跟_source JSON 里存的数据确实不一样,而我们平常搜索查看的都是从 JSON 里释放出来的,所以才会如此?

为了验证我的猜测,做了一个请求测试:

# curl es.domain.com:9200/logstash-accesslog-2015.04.03/nginx/_search?q=_id:AUx-QvSBS-dhpiB8_1f1\&pretty -d '{     
        "fields": ["requestTime", "bodySent"],     
        "script_fields" : {         
            "test1" : {             
                "script" : "doc[\"requestTime\"].value"         
            },         
            "test3" : {             
                "script" : "_source.bodySent / _source.requestTime"         
            },         
            "test2" : {             
                "script" : "doc[\"requestTime\"].value * 1000"         
            }     
         } 
     }'

得到的结果如下:

{   
    "took" : 43,   
    "timed_out" : false,   
    "_shards" : {     
    "total" : 56,     
    "successful" : 56,     
    "failed" : 0   
    },   
    "hits" : {     
        "total" : 1,     
        "max_score" : 1.0,     
        "hits" : [ {       
        "_index" : "logstash-accesslog-2015.04.03",       
        "_type" : "nginx",       
        "_id" : "AUx-QvSBS-dhpiB8_1f1",       
        "_score" : 1.0,       
        "fields" : {         
            "test1" : [ 4603039107142836552 ],         
            "test2" : [ -8646911284551352000 ],         
            "requestTime" : [ 0.54 ],         
            "test3" : [ 2444.4444444444443 ],         
            "bodySent" : [ 1320 ]       
            }     
        } ]   
    } 
}

果然!直接读取的字段,以及采用 _source.fieldname 方式读取的内容,都是正确的;而采用doc['fieldname'].value 获取的内存数据,就不对。(0.54 存成 long 型会变成 4603039107142836552。这个 460 还正好能跟 540 凑成 1000,应该是某种特定存法,不过这里我就没深究了)

再作下一步验证。我们知道,ES 数据的映射是根据第一条数据的类型确定的,之后的数据如何类型跟已经成型的映射不统一,那么写入会失败。现在这个 nginx 和 apache 两个类型在 requestTime 字段上的映射是不一样的,但是内存里却并没有按照映射来处理。那么,我往一个类型下写入另一个类型映射要求的数据,会报错还是会通过呢?

# curl -XPOST es.domain.com:9200/test/t1/1 -d '{"key":1}' 
{"_index":"test","_type":"t1","_id":"1","_version":1,"created":true} 
# curl -XPOST es.domain.com:9200/test/t2/1 -d '{"key":2.2}' 
{"_index":"test","_type":"t2","_id":"1","_version":1,"created":true} 
# curl -XPOST es.domain.com:9200/test/t1/2 -d '{"key":2.2}' 
{"_index":"test","_type":"t1","_id":"2","_version":1,"created":true} 
# curl -XPOST es.domain.com:9200/test/t2/2 -d '{"key":1}' 
{"_index":"test","_type":"t2","_id":"2","_version":1,"created":true} 
# curl -XPOST es.domain.com:9200/test/t1/3 -d '{"key":"1"}' 
{"_index":"test","_type":"t1","_id":"3","_version":1,"created":true} 
# curl -XPOST es.domain.com:9200/test/t2/3 -d '{"key":"1"}' 
{"_index":"test","_type":"t2","_id":"3","_version":1,"created":true} 
# curl -XPOST es.domain.com:9200/test/t2/4 -d '{"key":"abc"}' 
{"error":"RemoteTransportException[[10.10.10.10][inet[/10.10.10.10:9300]][indices:data/write/index]]; nested: MapperParsingException[failed to parse [key]]; nested: NumberFormatException[For input string: \"abc\"]; ","status":400} 
# curl -XGET es.domain.com:9200/test/_mapping 
{"test":{"mappings":{"t1":{"properties":{"key":{"type":"long"}}},"t2":{"properties":{"key":{"type":"double"}}}}}}

结果出来了,在映射相互冲突以后,实际数据只要是 numeric detect 能通过的,就都通过了!

BTW: kibana 4 中,已经会对这种情况以黄色感叹号图标做出提示;而根据官方消息,ES 未来会在 2.0 版正式杜绝这种可能。


本文转载自:http://chenlinux.com/2015/04/03/types-mapping-conflict-in-one-index/

共有 人打赏支持
上一篇: rsyslog队列参数
下一篇: uniupload mapping
MrYx3en
粉丝 9
博文 131
码字总数 30542
作品 0
宝鸡
系统管理员
私信 提问
ES6-映射(mapping)

1.mapping映射概述 我们习惯上对ElasticSearch和数据库做了一些对比,索引(index)相当于数据库,类型(type)相当于数据表,映射(Mapping)相当于数据表的表结构。 ElasticSearch中的映射(M...

贾峰uk
07/02
0
0
ElasticSearch学习笔记4--核心概念解读

4.1 索引 索引(index)是ElasticSearch存放具体数据的地方,是一类具有相似特征的文档的集合。ElasticSearch中索引的概念具有不同意思,这里的索引相当于关系数据库中的一个数据库实例(databa...

荆辰曦
09/05
0
0
如何用 Node.js 和 Elasticsearch 构建搜索引擎

Elasticsearch 是一款开源的搜索引擎,由于其高性能和分布式系统架构而备受关注。本文将讨论其关键特性,并手把手教你如何用它创建 Node.js 搜索引擎。 Elasticsearch 概述 Elasticsearch 底...

oschina
2016/09/29
10.2K
6
分布式搜索引擎Elasticsearch安装配置

分布式搜索引擎Elasticsearch 介绍 Elasticsearch是一个基于Lucene的开源分布式搜索引擎,具有分布式多用户能力。Elasticsearch是用java开发,提供Restful接口,能够达到实时搜索、高性能计算...

汪兴
2015/04/01
0
0
[翻译] 使用ElasticSearch,Kibana,ASP.NET Core和Docker可视化数据

原文地址:http://www.dotnetcurry.com/aspnet/1354/elastic-search-kibana-in-docker-dotnet-core-app 想要轻松地通过许多不同的方式查询数据,甚至是从未预料到的方式?想要以多种方式可视...

张蘅水
2017/04/08
0
0

没有更多内容

加载失败,请刷新页面

加载更多

大数据学习有哪几个步骤

目前大数据行业异常火爆,不少人都对大数据充满了兴趣,其中有大部分人都从没接触过大数据,对于应该如何学习大数据一头雾水。大数据学习并不是高深莫测的,虽然它并没有多简单,但是通过努力...

董黎明
18分钟前
4
0
shell习题_3

1:监控httpd的进程;每隔10s检测一次服务器的httpd的进程数,如果大于500则自动重启httpd服务;并检测是否启动成功; 如果没有正常启动还需要再启动一次,最大不成功数超过五次立即发邮件给管理...

芬野de博客
18分钟前
1
0
Android 9.0 优势探讨

我们来谈论一下 Android。尽管 Android 只是一款内核经过修改的 Linux,但经过多年的发展,Android 开发者们(或许包括正在阅读这篇文章的你)已经为这个平台的演变做出了很多值得称道的贡献...

问题终结者
35分钟前
4
0
vue 组件使用中的一些细节点

细节一 基础例子 运行结果: 以上大家都懂,这边就不多说,回到代码里,有时候我们需要 tbody 里面每一行是一个子组件,那我们代码可以怎么写呢?我们可以这样写,定义一个全局组件,如下: ...

peakedness丶
42分钟前
2
0
vue 之 css module的使用方法

动手之前先配置项目,网上很多文章说需要下载css-loader插件,Vue中的vue-loader已经集成了 CSS Modules,因此删掉也能正常运行 在vue.config.js中添加如下配置 `css: {``loaderOptions: ...

前端小攻略
46分钟前
2
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部