【问题标题】:Elasticsearch: Append new elements to nested array of objectsElasticsearch:将新元素附加到嵌套的对象数组
【发布时间】:2019-07-18 13:33:49
【问题描述】:

我正在尝试将新项目添加到来自特定文档的嵌套对象数组中。 我已经搜索过,似乎部分文档的更新不支持我需要的内容,它用新元素替换了整个数组。 所以我进行了脚本更新,它通过 REST API 按预期工作:

PUT /transactions
{
    "mappings": {
        "_doc": {
            "properties": {
                "userId": { "type": "keyword" },
                "transactions": {
                    "type": "object",
                    "properties": {
                        "date": { "type": "date" },
                        "amount": { "type": "double" }
                    }
                }
            }
        }
    }
}

POST /transactions/_doc/1
{
    "userId": "123",
    "transactions": [
        { "date": "2019-07-15T10:32:02Z", "amount": 122 },
        { "date": "2019-07-17T22:09:43Z", "amount": 560 }
    ]
}

POST /transactions/_doc/1/_update
{
    "script": {
        "source": "ctx._source.transactions.addAll(params.transactions)",
        "params": {
            "transactions": [
                { "date": "2019-07-14T21:10:22Z", "amount": 890 },
                { "date": "2019-07-15T15:56:18Z", "amount": 54 }
            ]
        }
    }
}

然后我将相同的脚本带到我的 Java 应用程序中,代码如下所示:

List<Transaction> transactions = Collections.singletonList(new Transaction(320));

Script script = new Script(
    Script.DEFAULT_SCRIPT_TYPE, Script.DEFAULT_SCRIPT_LANG,
    "ctx._source.transactions.addAll(params.transactions);",
    Collections.singletonMap("transactions", transactions));

transportClient
    .prepareUpdate("transactions", "_doc", 1)
    .setFetchSource(false);
    .setScript(script);
    .get();

执行上面的代码时,我得到以下远程异常:

Caused by: java.io.IOException: can not write type [class com.example.model.Transaction]
    at org.elasticsearch.common.io.stream.StreamOutput.writeGenericValue(StreamOutput.java:713)
    at org.elasticsearch.common.io.stream.StreamOutput.lambda$static$9(StreamOutput.java:599)
    at org.elasticsearch.common.io.stream.StreamOutput.writeGenericValue(StreamOutput.java:711)
    at org.elasticsearch.common.io.stream.StreamOutput.lambda$static$11(StreamOutput.java:621)
    at org.elasticsearch.common.io.stream.StreamOutput.writeGenericValue(StreamOutput.java:711)
    at org.elasticsearch.common.io.stream.StreamOutput.writeMap(StreamOutput.java:494)
    at org.elasticsearch.script.Script.writeTo(Script.java:533)
    ...

如果我将列表序列化为字符串,则会得到此异常:

org.elasticsearch.common.io.stream.NotSerializableExceptionWrapper: class_cast_exception: Cannot cast java.lang.String to java.util.Collection

最后,我的问题是如何使用 Java API(Transport Client,Elasticsearch 6.3.2)实现这一点?

另一种方法是获取整个文档,对其进行反序列化,附加一个新事务,然后更新整个文档,但这似乎有点矫枉过正,可能会降低性能。

【问题讨论】:

  • 你用的是什么版本的ES?
  • 如问题所述,6.3.2.
  • 对不起,我的错。被我溜走了。道斯的答案有帮助吗?
  • 是的,成功了,谢谢!
  • 太棒了...很高兴我能帮上忙

标签: java elasticsearch


【解决方案1】:

我只是好奇地看了source code,来自writeGenericValue方法,看起来ES不支持任何自定义对象的写入,除了在多个if else语句中处理的对象(Object [],列表、地图、ReadableInstant、BytesReference)。

从堆栈跟踪看来,script.writeTo 正在尝试将 Transaction 对象写入输出流,但没有这样做。将Transaction 对象转换为单独的地图然后发送它可能会解决问题。

【讨论】:

    猜你喜欢
    • 2017-08-05
    • 2015-09-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-11-21
    相关资源
    最近更新 更多