UTF8编码长度超过最大长度32766

时间:2014-06-03 16:06:57

标签: elasticsearch

我已经将我的Elasticsearch集群从1.1升级到1.2,并且在索引一个稍大的字符串时出错。

{
  "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" }
      }
    }
  }
}

我搜索了文档,但未发现任何与最大字段大小相关的内容。 根据{{​​3}}部分,我不明白为什么我应该为not_analyzed字段“更正分析器”。

10 个答案:

答案 0 :(得分:61)

因此,您遇到的问题是单个术语的最大大小。当您将字段设置为not_analyzed时,它会将其视为一个单独的术语。底层Lucene索引中单个术语的最大大小为32766字节,我认为这是硬编码。

您的两个主要选项是将类型更改为二进制或继续使用字符串,但将索引类型设置为“no”。

答案 1 :(得分:30)

如果你真的希望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"但是对于其他人发现这个问题后,像我一样,搜索那个例外,那么你的选择是:

  • 设置"index": "no"
  • 设置"index": "analyze"
  • 设置"index": "not_analyzed""ignore_above": 256

这取决于您是否以及如何过滤该属性。

答案 2 :(得分:7)

有一个比John发布的更好的选择。因为使用该解决方案,您无法再搜索该值。

回到问题:

问题是默认字段值将用作单个术语(完整字符串)。如果该术语/字符串长于32766字节,则无法存储在Lucene中。

较早版本的Lucene仅在术语太长时才会注册警告(并忽略该值)。较新的版本会抛出异常。请参阅错误修正:https://issues.apache.org/jira/browse/LUCENE-5472

<强>解决方案:

最佳选择是在字段上使用长字符串值定义(自定义)分析器。分析器可以用较小的字符串/术语分割长字符串。这将解决太长期的问题。

如果您正在使用该功能,请不要忘记在“_all”字段中添加分析器。

可以使用REST api测试分析仪。 http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/indices-analyze.html

答案 3 :(得分:2)

我需要将映射的index部分更改为no而不是not_analyzed。这样,该值不会被编入索引。它仍然可以在返回的文档中找到(来自搜索,获取,...),但我无法查询它。

答案 4 :(得分:1)

处理超出Lucene限制的令牌的一种方法是使用truncate过滤器。类似于ignore_above的关键字。为了演示,我正在使用5。 Elasticsearch建议使用ignore_above = 32766/4 = 8191,因为UTF-8字符最多可以占用4个字节。 https://www.elastic.co/guide/en/elasticsearch/reference/6.3/ignore-above.html

curl -H'Content-Type:application/json' localhost:9200/_analyze -d'{
  "filter" : [{"type": "truncate", "length": 5}],
  "tokenizer": {
    "type":    "pattern"
  },
  "text": "This movie \n= AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
}'

输出:

{
  "tokens": [
    {
      "token": "This",
      "start_offset": 0,
      "end_offset": 4,
      "type": "word",
      "position": 0
    },
    {
      "token": "movie",
      "start_offset": 5,
      "end_offset": 10,
      "type": "word",
      "position": 1
    },
    {
      "token": "AAAAA",
      "start_offset": 14,
      "end_offset": 52,
      "type": "word",
      "position": 2
    }
  ]
}

答案 5 :(得分:0)

我通过改变我的分析仪解决了这个问题。

electric-indent-mode

答案 6 :(得分:0)

如果您使用searchkick,请将elasticsearch升级为>= 2.2.0&amp;确保您使用的是searchkick 1.3.4或更高版本。

此版本的searchkick默认设置ignore_above = 256,因此当UTF&gt;时,您不会收到此错误32766.

讨论here

答案 7 :(得分:0)

在Solr v6 +中,我将字段类型更改为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"/>

答案 8 :(得分:0)

使用logstash索引这些长消息,我使用此过滤器来截断长字符串:

    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 字段,以便我可以按大小对最长的邮件进行排序。

它还将长消息标记添加到超过32000kb的标记,以便我可以轻松选择它们。

如果您打算完全索引这些长消息,它无法解决问题,但如果像我一样,不希望首先将它们放在elasticsearch中并且想要跟踪它们来修复它,那么它就是工作解决方案。

答案 9 :(得分:0)

我在Drupal的Search api attachments模块中偶然发现了同样的错误消息:

  

文档在字段中包含至少一个巨大的术语=&#34; saa_saa_file_entity&#34; (其UTF8编码长度超过最大长度32766),所有这些都被跳过。请更正分析仪以不生成此类条款。

将字段类型从string更改为Fulltext(在 / admin / config / search / search-api / index / elastic_index / fields 中)解决了我的问题