【问题标题】:UTF8 encoding is longer than the max length 32766UTF8 编码大于最大长度 32766
【发布时间】:2014-07-24 01:35:35
【问题描述】:

我已将我的 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" }
      }
    }
  }
}

我已经搜索了文档,但没有找到与最大字段大小相关的任何内容。 根据core types 部分,我不明白为什么我应该为not_analyzed 字段“更正分析器”。

【问题讨论】:

  • 也与其他使用 Lucene 索引的软件相关,例如 Solr。
  • 如何用prefix值说,解码成文本?我的意思是,如何解释这个值?

标签: elasticsearch


【解决方案1】:

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

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

【讨论】:

  • 这正是 Karmi(来自 Elasticsearch 核心团队)帮助我得出的结论。正如我所说,我已经选择了"index": "no"
  • 仅供参考,这是最近在底层 lucene 中发生的变化,以前默默地忽略了这些巨大的条款,而现在它正在抛出异常。
  • 在 ES 5.4.1 上,你仍然需要禁用 doc_values
【解决方案2】:

如果你真的想在属性上打开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

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

【讨论】:

  • 如果您仍需要在现场进行排序,这是最好的解决方案。
  • 值得一提,如果数据已经存在于类型中,最好使用ignore_above选项,这是一个非破坏性更改,而不是index:no,这是一个破坏性更改,你会必须导出导入数据才能申请。
【解决方案3】:

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

回到问题:

问题在于,默认情况下,字段值将用作单个术语(完整字符串)。如果该术语/字符串长于 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

【讨论】:

  • 非常有趣的答案,但是在哪里可以找到这样的自定义分析器,它将字符串字段拆分为标记,但在搜索请求期间“组合”这些标记的整个值?
  • 您可以使用elastic.co/guide/en/elasticsearch/reference/1.5/… 上的默认/自定义分析器。不要忘记也可以使用/需要分析器的 _all 字段(或禁用字段以解决问题)。
【解决方案4】:

我需要将映射的index 部分更改为no 而不是not_analyzed。这样该值就不会被索引。它在返回的文档中仍然可用(通过搜索、获取等),但我无法查询它。

【讨论】:

  • @Adrian 正如我所说,我已将 mapping.request.properties.request_body.indexnot_analyzed 更改为 no 并更新了我在 Elasticsearch 中的索引映射。
【解决方案5】:

处理超过 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
    }
  ]
}

【讨论】:

  • 我们如何将它与关键字字段一起使用?
  • 我只会使用 ignore_above 作为关键字字段。
【解决方案6】:

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

这个版本的searchkick默认设置ignore_above = 256,所以当UTF > 32766时不会出现这个错误。

这是在here 讨论的。

【讨论】:

    【解决方案7】:

    我通过更换我的分析仪解决了这个问题。

    {
        "index" : {
            "analysis" : {
                "analyzer" : {
                    "standard" : {
                        "tokenizer": "standard",
                        "filter": ["standard", "lowercase", "stop"]
                    }
                }
            }
        }
    }
    

    【讨论】:

    • 这对忽略长标记有何帮助?
    【解决方案8】:

    在 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"/>
    

    【讨论】:

      【解决方案9】:

      使用 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 的消息添加 long message 标签,以便我可以轻松选择它们。

      如果您打算完全索引那些长消息,它并不能解决问题,但是如果像我一样,不想一开始就将它们放在 elasticsearch 中并希望跟踪它们以修复它,那么它是一个工作解决方案。

      【讨论】:

        【解决方案10】:

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

        文档在 field="saa_saa_file_entity" 中包含至少一个巨大的术语(其 UTF8 编码长于最大长度 32766),所有这些都被跳过。请更正分析器以不产生此类术语。

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

        【讨论】:

          猜你喜欢
          • 2019-09-04
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2018-08-26
          • 1970-01-01
          相关资源
          最近更新 更多