elasticsearch id字段查询时怎么对不同字段赋予不同的权重

Elasticsearch 同一索引不同类型下同名字段的映射冲突实例
来源:易贤网&& 阅读:699 次&&日期: 15:58:34
温馨提示:易贤网小编为您整理了“Elasticsearch 同一索引不同类型下同名字段的映射冲突实例”,方便广大网友查阅!
这个标题肯定绕晕很多人吧。具体说明一下场景就明白了:Nginx 和 Apache 的访问日志,因为都属于网站访问,所以写入到同一个索引的不同类型下,比方 logstash-accesslog-/nginx 和 logstash-accesslog-/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 :9200/logstash-accesslog-/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-", "_type" : "nginx", "_id" : "AUx-QvSBS-dhpiB8_1f1", "_score" : 1.0, "fields" : { "test1" : [ 2836552 ], "test2" : [ -1352000 ], "requestTime" : [ 0.54 ], "test3" : [ 444443 ], "bodySent" : [ 1320 ] } } ] }}果然!直接读取的字段,以及采用 _source.fieldname 方式读取的内容,都是正确的;而采用 doc['fieldname'].value 获取的内存数据,就不对。(0.54 存成 long 型会变成 2836552。这个 460 还正好能跟 540 凑成 1000,应该是某种特定存法,不过这里我就没深究了)
再作下一步验证。我们知道,ES 数据的映射是根据第一条数据的类型确定的,之后的数据如何类型跟已经成型的映射不统一,那么写入会失败。现在这个 nginx 和 apache 两个类型在 requestTime 字段上的映射是不一样的,但是内存里却并没有按照映射来处理。那么,我往一个类型下写入另一个类型映射要求的数据,会报错还是会通过呢?
# curl -XPOST :9200/test/t1/1 -d '{"key":1}'{"_index":"test","_type":"t1","_id":"1","_version":1,"created":true}# curl -XPOST :9200/test/t2/1 -d '{"key":2.2}'{"_index":"test","_type":"t2","_id":"1","_version":1,"created":true}# curl -XPOST :9200/test/t1/2 -d '{"key":2.2}'{"_index":"test","_type":"t1","_id":"2","_version":1,"created":true}# curl -XPOST :9200/test/t2/2 -d '{"key":1}'{"_index":"test","_type":"t2","_id":"2","_version":1,"created":true}# curl -XPOST :9200/test/t1/3 -d '{"key":"1"}'{"_index":"test","_type":"t1","_id":"3","_version":1,"created":true}# curl -XPOST :9200/test/t2/3 -d '{"key":"1"}'{"_index":"test","_type":"t2","_id":"3","_version":1,"created":true}# curl -XPOST :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 :9200/test/_mapping{"test":{"mappings":{"t1":{"properties":{"key":{"type":"long"}}},"t2":{"properties":{"key":{"type":"double"}}}}}}结果出来了,在映射相互冲突以后,实际数据只要是 numeric detect 能通过的,就都通过了!
BTW: kibana 4 中,已经会对这种情况以黄色感叹号图标做出提示;而根据官方消息,ES 未来会在 2.0 版正式杜绝这种可能。
更多信息请查看
更多信息请查看
【】&&&&&【点此处查询各地各类考试咨询QQ号码及交流群】
易贤网手机网站地址:
由于各方面情况的不断调整与变化,易贤网提供的所有考试信息和咨询回复仅供参考,敬请考生以权威部门公布的正式信息和咨询为准!
相关阅读 & & &
&&& &nbsp&nbsp&nbsp会员注册
本站不参与评论!()
自觉遵守:爱国、守法、自律、真实、文明的原则
尊重网上道德,遵守中华人民共和国各项有关法律法规
严禁发表危害国家安全,破坏民族团结、国家宗教政策和社会稳定,含侮辱、诽谤、教唆、淫秽等内容的评论
承担一切因您的行为而直接或间接导致的民事或刑事法律责任
您在本站发表的评论,本站有权保留、转载、引用或者删除
参与本评论即表明您已经阅读并接受上述条款multi_match查询
multi_match查询提供了一个简便的方法用来对多个字段执行相同的查询。
存在几种类型的multi_match查询,其中的3种正好和在一节中提到的几种类型相同:best_fields,most_fields以及cross_fields。
默认情况下,该查询以best_fields类型执行,它会为每个字段生成一个match查询,然后将这些查询包含在一个dis_max查询中。下面的dis_max查询:
&dis_max&: {
&queries&:
&match&: {
&title&: {
&query&: &Quick brown fox&,
&minimum_should_match&: &30%&
&match&: {
&query&: &Quick brown fox&,
&minimum_should_match&: &30%&
&tie_breaker&: 0.3
可以通过multi_match简单地重写如下:
&multi_match&: {
&Quick brown fox&,
&best_fields&,
[ &title&, &body& ],
&tie_breaker&:
&minimum_should_match&: &30%&
注意到以上的type属性为best_fields。&minimum_should_match和operator参数会被传入到生成的match查询中。
在字段名中使用通配符
字段名可以通过通配符指定:任何匹配了通配符的字段都会被包含在搜索中。你可以通过下面的查询来匹配book_title,chapter_title以及section_title字段:
&multi_match&: {
&Quick brown fox&,
&fields&: &*_title&
提升个别字段
个别字段可以通过caret语法(^)进行提升:仅需要在字段名后添加^boost,其中的boost是一个浮点数:
&multi_match&: {
&Quick brown fox&,
&fields&: [ &*_title&, &chapter_title^2& ]
chapter_title字段的boost值为2,而book_title和section_title字段的boost值为默认的1。
多数字段(Most Fields)
全文搜索是一场召回率(Recall) - 返回所有相关的文档,以及准确率(Precision) - 不返回无关文档,之间的战斗。目标是在结果的第一页给用户呈现最相关的文档。
为了提高召回率,我们会广撒网 - 不仅包括精确匹配了用户搜索词条的文档,还包括了那些我们认为和查询相关的文档。如果一个用户搜索了&quick brown fox&,一份含有fast foxes的文档也可以作为一个合理的返回结果。
如果我们拥有的相关文档仅仅是含有fast foxes的文档,那么它会出现在结果列表的顶部。但是如果我们有100份含有quick brown fox的文档,那么含有fast foxes的文档的相关性就会变低,我们希望它出现在结果列表的后面。在包含了许多可能的匹配后,我们需要确保相关度高的文档出现在顶部。
一个用来调优全文搜索相关性的常用技术是将同样的文本以多种方式索引,每一种索引方式都提供了不同相关度的信号(Signal)。主要字段(Main field)中含有的词条的形式是最宽泛的(Broadest-matching),用来尽可能多的匹配文档。比如,我们可以这样做:
使用一个词干提取器来将jumps,jumping和jumped索引成它们的词根:jump。然后当用户搜索的是jumped时,我们仍然能够匹配含有jumping的文档。包含同义词,比如jump,leap和hop。移除变音符号或者声调符号:比如,ésta,está和esta都会以esta被索引。
但是,如果我们有两份文档,其中之一含有jumped,而另一份含有jumping,那么用户会希望第一份文档的排序会靠前,因为它含有用户输入的精确值。
我们可以通过将相同的文本索引到其它字段来提供更加精确的匹配。一个字段可以包含未被提取词干的版本,另一个则是含有变音符号的原始单词,然后第三个使用了shingles,用来提供和相关的信息。这些其它字段扮演的角色就是信号(Signals),它们用来增加每个匹配文档的相关度分值。能够匹配的字段越多,相关度就越高。
如果一份文档能够匹配具有最宽泛形式的主要字段(Main field),那么它就会被包含到结果列表中。如果它同时也匹配了信号字段,它会得到一些额外的分值用来将它移动到结果列表的前面。
我们会在本书的后面讨论同义词,单词邻近度,部分匹配以及其他可能的信号,但是我们会使用提取了词干和未提取词干的字段的简单例子来解释这个技术。
多字段映射(Multifield
第一件事就是将我们的字段索引两次:一次是提取了词干的形式,一次是未提取词干的形式。为了实现它,我们会使用多字段(Multifields),在中我们介绍过:
DELETE /my_index
PUT /my_index
&settings&: { &number_of_shards&: 1 },
&mappings&: {
&my_type&: {
&properties&: {
&title&: {
&analyzer&: &english&,
&fields&: {
&analyzer&: &standard&
title字段使用了english解析器进行词干提取。 title.std字段则使用的是standard解析器,因此它没有进行词干提取。
下一步,我们会索引一些文档:
PUT /my_index/my_type/1
{ &title&: &My rabbit jumps& }
PUT /my_index/my_type/2
{ &title&: &Jumping jack rabbits& }
以下是一个简单的针对title字段的match查询,它查询jumping rabbits:
GET /my_index/_search
&query&: {
&match&: {
&title&: &jumping rabbits&
它会变成一个针对两个提干后的词条jump和rabbit的查询,这要得益于english解析器。两份文档的title字段都包含了以上两个词条,因此两份文档的分值是相同的:
&_id&: &1&,
&_score&: 0.,
&_source&: {
&title&: &My rabbit jumps&
&_id&: &2&,
&_score&: 0.,
&_source&: {
&title&: &Jumping jack rabbits&
如果我们只查询title.std字段,那么只有文档2会匹配。但是,当我们查询两个字段并将它们的分值通过bool查询进行合并的话,两份文档都能够匹配(title字段也匹配了),而文档2的分值会更高一些(匹配了title.std字段):
GET /my_index/_search
&query&: {
&multi_match&: {
&jumping rabbits&,
&most_fields&,
&fields&: [ &title&, &title.std& ]
在上述查询中,由于我们想合并所有匹配字段的分值,因此使用的类型为most_fields。这会让multi_match查询将针对两个字段的查询子句包含在一个bool查询中,而不是包含在一个dis_max查询中。
&_id&: &2&,
&_score&: 0.8226396,
&_source&: {
&title&: &Jumping jack rabbits&
&_id&: &1&,
&_score&: 0.,
&_source&: {
&title&: &My rabbit jumps&
此时,文档2的分值比文档1的高许多。
我们使用了拥有宽泛形式的title字段来匹配尽可能多的文档 - 来增加召回率(Recall),同时也使用了title.std字段作为信号来让最相关的文档能够拥有更靠前的排序(译注:增加了准确率(Precision))。
每个字段对最终分值的贡献可以通过指定boost值进行控制。比如,我们可以提升title字段来让该字段更加重要,这也减小了其它信号字段的影响:
GET /my_index/_search
&query&: {
&multi_match&: {
&jumping rabbits&,
&most_fields&,
[ &title^10&, &title.std& ]
本文已收录于以下专栏:
相关文章推荐
多字段搜索(Multifield Search)
本文翻译自官方指南的Multifield Search一章。
查询很少是只拥有一个match查询子句的查询。我们经常需要对一个或者多个字段...
最佳字段(Best Fields)
假设我们有一个让用户搜索博客文章的网站,就像这两份文档一样:
PUT /my_index/my_type/1
&title&: &Qui...
多词查询(Multi-word Queries)
如果我们一次只能搜索一个词,那么全文搜索就会显得相当不灵活。幸运的是,通过match查询来实现多词查询也同样简单:
GET /my_ind...
match查询是如何使用bool查询的
现在,你也许意识到了使用了match查询的多词查询只是简单地将生成的term查询包含在了一个bool查询中。通过默认的or操作符,每个term查询都以一个k语...
跨字段实体搜索(Cross-fields Entity Search)
现在让我们看看一个常见的模式:跨字段实体搜索。类似person,product或者address这样的实体,它们的信息会分...
多值字段(Multivalue Fields)
在多值字段上使用短语匹配会产生古怪的行为:
PUT /my_index/groups/1
&names&: [ &John Abraha...
自定义_all字段
在元数据:_all字段中,我们解释了特殊的_all字段会将其它所有字段中的值作为一个大字符串进行索引。尽管将所有字段的值作为一个字段进行索引并不是非常灵活。如果有一个自定义的_...
es中的查询请求有两种方式,一种是简易版的查询,另外一种是使用JSON完整的请求体,叫做结构化查询(DSL)。
由于DSL查询更为直观也更为简易,所以大都使用这种方式。
DSL查询是POST过去一...
最近在使用elasticsearch的multi_match搜索时候,使用下面的body对一个字段下的所有字段进行递归搜索,但是当这些子字段出现数值类型的时候,就会报异常了,具体讨论可以参考
java在不同系统有不同的换行符
在文章中的字符串分割,经常要使用换行分割,
在Windows中要使用&\r\n&
String[] arr = fileContet.splite(&...
他的最新文章
讲师:王哲涵
讲师:韦玮
您举报文章:
举报原因:
原文地址:
原因补充:
(最多只允许输入30个字)请教elasticsearch自定义结果集过滤如何支持? - 知乎9被浏览690分享邀请回答0添加评论分享收藏感谢收起0添加评论分享收藏感谢收起1 个回答被折叠()问题对人有帮助,内容完整,我也想知道答案
问题没有实际价值,缺少关键内容,没有改进余地
想使用ES作为数据库,使用java api调用,需要group by一个Field,同时对多个Field做sum、avg等等,但是发现只有TermsBuilder有subAggregation方法,可以添加子聚合,SumBuilder,AvgBuilder都不能添加subAggregation?
使用SQL语句表达类似于:
select field1,sum(field2),sum(field3) from table group by field1
有人遇到过这种情况吗,是怎么解决的?
答案对人有帮助,有参考价值
答案没帮助,是错误的答案,答非所问
SearchRequestBuilder srb = client.prepareSearch(indexName)
.setTypes(typeName)
.setSearchType(SearchType.QUERY_THEN_FETCH);
TermsBuilder field1Terms = AggregationBuilders.terms("group_by_field1").field("field1").size(0);
SumBuilder field2Sum = AggregationBuilders.sum("sum_field2").field("field2");
SumBuilder field3Sum = AggregationBuilders.sum("sum_field3").field("field3");
field1Terms.subAggregation(field2Sum ).subAggregation(field3Sum );
srb.addAggregation(pIdTerms);
SearchResponse sr = srb.execute().actionGet();
答案对人有帮助,有参考价值
答案没帮助,是错误的答案,答非所问
首先先感谢大牛,分享技术,我是今天第一次使用es,有很多不会的还需多多学习。请问srb.addAggregation(pIdTerms);
pIdTerms字段 怎么理解, 如何使用,如果可以请将详细代码,发送到邮箱,感激不尽,,
同步到新浪微博
分享到微博?
Hi,欢迎来到 SegmentFault 技术社区!⊙▽⊙ 在这里,你可以提出编程相关的疑惑,关注感兴趣的问题,对认可的回答投赞同票;大家会帮你解决编程的问题,和你探讨技术更新,为你的回答投上赞同票。
明天提醒我
关闭理由:
删除理由:
忽略理由:
推广(招聘、广告、SEO 等)方面的内容
与已有问题重复(请编辑该提问指向已有相同问题)
答非所问,不符合答题要求
宜作评论而非答案
带有人身攻击、辱骂、仇恨等违反条款的内容
无法获得确切结果的问题
非开发直接相关的问题
非技术提问的讨论型问题
其他原因(请补充说明)
我要该,理由是:推荐这篇日记的豆列
&&&&&&&&&&&&

我要回帖

更多关于 elasticsearch 全字段 的文章

 

随机推荐