我可以将标签添加到 Elastic Search 文档中的 "deeper" 键吗?

Can i add tags to a "deeper" key in an Elastic Search document?

我有带标签的产品,标签在标签类型中。

这是我添加到索引中的示例文档

 {
        "_index" : "products",
        "_type" : "_doc",
        "_id" : "1219",
        "_score" : 1.0,
        "_source" : {
          "id" : "1219",
          "product_no" : "26426492261",
          "merchant_id" : 11,
          "name" : "Apple »Magic Keyboard für das 12,9\" iPad Pro (4. Generation)« iPad-Tastatur",
          "category" : "Technik>Multimedia>Zubehör>Tastatur>iPad Tastatur",
          "deep_link" : "https://foo",
          "short_description" : null,
          "long_description" : "Apple:",
          "brand" : "Apple",
          "merchant_image_url" : "http://something",
          "tagtypes" : [
            [
              {
                "Memory" : [ ]
              }
            ]
          ]
        }
      },

标记类型“Memory”是在索引产品时动态创建的。

我尝试向该键添加标签

 //attach tags also to ES
                        $params = [
                            'index' => 'products',
                            'id' => $product['_id'],
                            'body' => [
                                'script' => [
                                    'source' => 'if (!ctx._source.tagtypes.'.$tagType->name.'.contains(params.tag)) { ctx._source.tagtypes.'.$tagType->name.'.add(params.tag) }',
                                    'lang' => 'painless',
                                    'params' => [
                                        'tag' => $tag->value
                                    ]
                                ]
                            ]

                        ];

但是我收到了类似

的错误

{"error":{"root_cause":[{"type":"illegal_argument_exception","reason":"failed to execute script"}],"type":"illegal_argument_exception","reason":"failed to execute script","caused_by":{"type":"script_exception","reason":"runtime error","script_stack":["if (!ctx._source.tagtypes[\"Memory\"].contains(params.tag)) { "," ^---- HERE"],"script":"if (!ctx._source.tagtypes[\"Memory\"].contains(params.tag)) { ctx._source.tagtypes[\"Memory\"].add(params.tag) }","lang":"painless","position":{"offset":16,"start":0,"end":60},"caused_by":{"type":"wrong_method_type_exception","reason":"cannot convert MethodHandle(List,int)int to (Object,String)String"}}},"status":400}

谁能帮我解决这个问题。我找不到任何关于它的文档,因为示例通常太基础了。

通常可以像这样保存到“更深的键”吗? 或者我可以将“标签”创建为简单列表(没有任何深度)

提前致谢 阿德里安!

您的字段 tagtypes 是对象数组的数组,对象数组本身包含一键数组。

当你处理这种“深层”结构时,你需要一些形式的迭代来更新它们。

For 循环是一个很好的起点,但它们通常会导致 java.util.ConcurrentModificationExceptions。因此,使用数据的临时副本更容易,然后在完成迭代后替换相应的 _source 属性:

{
  "query": {
    "match_all": {}
  },
  "script": {
    "source": """
      if (ctx._source.tagtypes == null) { return; }
      
      def originalTagtypes = ctx._source.tagtypes;
      def newTagtypes = [];
      
      for (outerGroup in originalTagtypes) {
        // keep what we've got
        newTagtypes.addAll(outerGroup);
        
        // group already present?
        def atLeastOneGroupContainsTag = outerGroup.stream().anyMatch(tagGroup -> tagGroup.containsKey(params.tag));
        
        // if not, add it as a hashmap of one single empty list
        if (!atLeastOneGroupContainsTag) {
          Map m = new HashMap();
          m.put(params.tag, []);
          newTagtypes.add(m);
        } 
      }
      
      ctx._source.tagtypes = [newTagtypes];
    """,
    "lang": "painless",
    "params": {
      "tag": "CPU"
    }
  }
}

这将最终像这样更新 tagtypes

{
 ...
  "tagtypes" : [
    [
      {
        "Memory" : [ ]
      },
      {
        "CPU" : [ ]        <---
      }
    ]
  ],
  ...
}

您说文档示例太基础了,您说得对。无耻插件:我最近 published a handbook 旨在解决这个问题。您会发现许多重要的脚本示例,以更好地理解 Painless 脚本语言。