UTF8编码比最大长度32766长
我已经将我的Elasticsearch集群从1.1升级到1.2,并且在索引一个有点大的string时遇到了错误。
{ "error": "IllegalArgumentException[Document contains at least one immense term in field=\"response_body\" (whose UTF8 encoding is longer than the max length 32766), all of which were skipped. Please correct the analyzer to not produce such terms. The prefix of the first immense term is: '[7b 22 58 48 49 5f 48 6f 74 65 6c 41 76 61 69 6c 52 53 22 3a 7b 22 6d 73 67 56 65 72 73 69]...']", "status": 500 }
索引的映射:
{ "template": "partner_requests-*", "settings": { "number_of_shards": 1, "number_of_replicas": 1 }, "mappings": { "request": { "properties": { "asn_id": { "index": "not_analyzed", "type": "string" }, "search_id": { "index": "not_analyzed", "type": "string" }, "partner": { "index": "not_analyzed", "type": "string" }, "start": { "type": "date" }, "duration": { "type": "float" }, "request_method": { "index": "not_analyzed", "type": "string" }, "request_url": { "index": "not_analyzed", "type": "string" }, "request_body": { "index": "not_analyzed", "type": "string" }, "response_status": { "type": "integer" }, "response_body": { "index": "not_analyzed", "type": "string" } } } } }
我search了文档,没有发现任何与最大字段大小有关的内容。 根据核心types部分,我不明白为什么我应该“更正分析器”为一个not_analyzed
字段。
所以你遇到了一个单一词汇的最大规模的问题。 当你把一个字段设置为not_analyzed时,它会把它当作一个单词。 底层Lucene索引中单个词语的最大大小是32766字节,我相信这是硬编码的。
您的两个主要选项是将types更改为二进制或继续使用string,但将索引types设置为“否”。
如果你真的不想not_analyzed
属性,因为你想做一些确切的过滤,那么你可以使用"ignore_above": 256
这里是我如何在php中使用它的一个例子:
'mapping' => [ 'type' => 'multi_field', 'path' => 'full', 'fields' => [ '{name}' => [ 'type' => 'string', 'index' => 'analyzed', 'analyzer' => 'standard', ], 'raw' => [ 'type' => 'string', 'index' => 'not_analyzed', 'ignore_above' => 256, ], ], ],
在你的情况下,你可能想按John Petrone告诉你的设置"index": "no"
但是对于后来发现这个问题的任何人,像我一样寻找这个Exception,那么你的select是:
- 设置
"index": "no"
- 设置
"index": "analyze"
- 设置
"index": "not_analyzed"
和"ignore_above": 256
这取决于是否以及如何过滤该属性。
有一个比John发布的更好的select。 因为使用该解决scheme,您无法再search该值。
回到问题:
问题是,默认情况下,字段值将被用作一个单词(完整的string)。 如果该字段/string比32766字节长,则不能将其存储在Lucene中。
旧版本的Lucene只会在条件过长时才会发出警告(并忽略该值)。 较新的版本会抛出exception。 请参阅bugfix: https : //issues.apache.org/jira/browse/LUCENE-5472
解:
最好的select是在长string值的字段上定义(自定义)分析器。 分析仪可以以较小的string/术语分割出长string。 这将解决太长期的问题。
如果您正在使用该function,请不要忘记在“_all”字段中添加一个分析器。
分析仪可以用REST API进行testing。 http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/indices-analyze.html
我需要将映射的index
部分更改为no
而不是not_analyzed
。 这样的价值是没有索引。 它仍然可以在返回的文档(从search,获取,…),但我不能查询它。
我通过更换分析仪来解决这个问题。
{ "index" : { "analysis" : { "analyzer" : { "standard" : { "tokenizer": "standard", "filter": ["standard", "lowercase", "stop"] } } } } }
如果您使用的是searchkick
, searchkick
升级到>= 2.2.0
并确保您使用的是Searchkick 1.3.4
或更高版本。
这个版本的searchkick默认设置了ignore_above = 256
,所以当UTF> 32766的时候你不会得到这个错误。
这在这里讨论。
在Solr v6 +中,我将字段types更改为text_general,并解决了我的问题。
<field name="body" type="string" indexed="true" stored="true" multiValued="false"/> <field name="id" type="string" multiValued="false" indexed="true" required="true" stored="true"/>
使用logstash来索引那些长消息,我使用这个filter来截断长string:
filter { ruby { code => "event.set('message_size',event.get('message').bytesize) if event.get('message')" } ruby { code => " if (event.get('message_size')) event.set('message', event.get('message')[0..9999]) if event.get('message_size') > 32000 event.tag 'long message' if event.get('message_size') > 32000 end " } }
它添加一个message_size字段,以便我可以按大小sorting最长的消息。
它还将长消息标签添加到那些超过32000kb的,所以我可以轻松地select它们。
如果你打算把这些长信息完全编入索引,它并不能解决问题,但是如果像我一样,不想把它们放在弹性search的首位,并且想跟踪它们来解决这个问题,那么这是一个可行的解决scheme。