索引整数和字符串的 JSON 数组时,ElasticSearch 抛出映射器解析异常

分享于2023年04月08日 elasticsearch elasticsearch-exception json python 问答
【问题标题】:ElasticSearch throwing mapper parsing exception when indexing JSON array of integers and strings索引整数和字符串的 JSON 数组时,ElasticSearch 抛出映射器解析异常
【发布时间】:2023-04-03 08:26:01
【问题描述】:

我正在尝试使用 python 从文件中提取 JSON 数组并将其输入到 ElasticSearch 中。数组如下所示:

{"name": [["string1", 1, "string2"],["string3", 2, "string4"], ... (variable length) ... ["string n-1", 3, "string n"]]}

ElasticSearch 在尝试索引数组时抛出 TransportError(400, mapper_parsing_exception, failed to parse)。我发现,每当我尝试向它提供包含字符串和整数的字符串时,ElasticSearch 有时会抛出相同的错误。因此,例如,以下内容有时会崩溃,有时会成功:

import json
from elasticsearch import Elasticsearch

es = Elasticsearch()

test = json.loads('{"test": ["a", 1, "b"]}')
print test
es.index(index, body=test)

这段代码是我可以在不破坏程序的情况下安全地注释掉的所有内容。我将 JSON 放入程序中,而不是从文件中读取它。我输入的实际字符串很长(否则我只会发布它们)并且总是会使程序崩溃。将 JSON 更改为 "test": ["a"] 将使其工作。如果上次崩溃,当前设置会崩溃,或者如果上次成功,则可以正常工作。到底是怎么回事?某种映射设置会解决这个问题吗?我还没有弄清楚如何设置具有可变数组长度的地图。我更愿意利用无模式输入,但我会采用任何可行的方法。

  • 这是您使用的实际代码吗?因为按原样,如果没有提供给 ElasticSearch 的有效连接配置,这将无法工作:例如: Elasticsearch(['http://user:secret@localhost:9200/']) 。此外,当您调用 index. es.index(index, body=test, id='my_id', doc_type='things') 时,您需要提供 doc_type id
  • 这个实际代码将返回我停留的异常。 Elasticsearch() 方法默认为 localhost:9200,我有一个 Elasticsearch 的本地实例正在运行。默认情况下, doc_type id 也可以完美处理。此代码在不处理包含混合变量的数组时成功执行。
  • 也许这会对你有所帮助。但这对我来说使用您的数据结构运行得非常好: pastebin.com/EQRgrk8M
  • 嗯,感谢您的帮助,但这并不能从一开始就修复数组大小写,也不能解决数组大小写失败后拒绝单个列表大小写的行为。也许问题出在我的 Elasticsearch 上?我会重新安装它。
  • 抱歉,我无法复制。我一直在尝试使用不同的数据结构,只要我传递有效的 json,它就可以工作。

【解决方案1】:

您的映射可能会遇到类型冲突。由于您已经表达了保持“无模式”的愿望,我假设您没有明确地为您的索引提供映射。这很好用,只需认识到您索引的 first 文档将确定索引的架构。之后您索引的每个文档都具有相同的字段(按名称),这些字段必须符合与第一个文档相同的类型。

Elasticsearch 对值数组没有任何问题。事实上,在底层,它将所有值都视为数组(具有一个或多个条目)。稍微令人担忧的是您选择的示例数组,它混合了字符串和数字类型。由于数组中的每个值都映射到名为“test”的字段,并且该字段可能只有一种类型,如果 ES 处理的第一个文档的第一个值是数字,它可能会将该字段分配为 long 类型.然后,将来包含不能很好地解析为数字的字符串的文档将在 Elasticsearch 中导致异常。

看看 documentation on Dynamic Mapping

无模式可能会很好,但在您的场景中,通过显式声明索引上的映射,至少为文档中的某些字段,您可能会取得更大的成功。如果您打算索引包含混合数据类型的数组,最好将该字段声明为 string 类型。

【讨论】:

  • 感谢您的撰写!我研究了定义映射并阅读了官方文档,但我无法弄清楚如何以 Elasticsearch 接受的方式定义固定长度列表的可变长度列表。我希望你能在这方面得到任何帮助。我还认为数据库过于严格地解释模式并拒绝以后不匹配的数组,就像你建议的那样,但即使我尝试只输入第一个数组,我也遇到了同样的崩溃,所以我认为那不是问题。
  • 或者,我可能不明白您所说的“固定长度列表”是什么意思?你能详细说明一下吗?
  • 顶部的数组正是我输入的内容,以及导致每次抛出此异常的原因。想象一系列产品评论,每个评论都有名称、评论和评分。不同的产品可能有不同数量的评论,但每条评论都会有这三个属性。它往往是大约 10-30 条评论,而评论本身大约是 1-3 句话。我还有许多其他产品数据完全按照我的代码的预期输入,但是尝试执行评论数组每次都会引发异常,即使我将其缩减为单个评论也是如此。
  • 明白了。是的,我相信这是因为 Elasticsearch 需要为您尝试索引的每个值提供一个字段名称。您提供了一个数组数组,而 ES 没有为您的内部数组的元素命名。您需要将您的“名称”字段调整为 object 类型,并为您的评论包含一组对象,而不是一组通用数组。