Фильтр скрипта ElasticSearch безболезненно по настраиваемым параметрам - PullRequest
0 голосов
/ 07 мая 2020

Я пытаюсь создать безболезненный скрипт для фильтрации массива вложенных полей с помощью массива настраиваемых параметров, по моему for l oop выдает ошибку.

Сопоставление

    {
        "documents": {
            "mappings": {
                "document": {
                    "properties": {
                        "properties": {
                            "type": "nested",
                            "properties": {
                                "key": {
                                    "type": "text",
                                    "fields": {
                                        "keyword": {
                                            "type": "keyword",
                                            "ignore_above": 256
                                        }
                                    }
                                },
                                "value": {
                                    "type": "text",
                                    "fields": {
                                        "keyword": {
                                            "type": "keyword",
                                            "ignore_above": 256
                                        }
                                    }
                                }
                            }
                        },
                        "performances": {
                            "properties": {
                                "key": {
                                    "type": "text",
                                    "fields": {
                                        "keyword": {
                                            "type": "keyword",
                                            "ignore_above": 256
                                        }
                                    }
                                },
                                "value": {
                                    "type": "double"
                                }
                            }
                        },
                        "name": {
                            "type": "text",
                            "fields": {
                                "keyword": {
                                    "type": "keyword",
                                    "ignore_above": 256
                                }
                            }
                        },
                        "id": {
                            "type": "long"
                        }
                    }
                }
            }
        }
    }

_source

    "_source": {
        "properties": [{
                "value": [
                    "D"
                ],
                "key": "M"
            },
            {
                "value": [
                    "2019-12-31"
                ],
                "key": "DOCUMENT_DATE"
            },
            {
                "isMultiValue": false,
                "value": [
                    "Yes"
                ],
                "key": "ACTIVE_DOCUMENT"
            },
        ],
        "performances": [
            {
                "value": 123,
                "key": "performance1"
            },
            {
                "value": 234,
                "key": "performance3"
            },
            {
                "value": 345,
                "key": "performance5"
            },
            {
                "value": -456,
                "key": "someKey"
            },
            {
                "value": -567,
                "key": "someOtherKey"
            },
        ],
        "name": "documentName43",
        "id": "1234"
    }

Скрипт выглядит так:

    {
        "query": {
            "bool": {
                "filter": [{
                        "nested": {
                            "path": "properties",
                            "query": {
                                "bool": {
                                    "filter": [{
                                            "match": {
                                                "properties.key.keyword": "ACTIVE_DOCUMENT"
                                            }
                                        },
                                        {
                                            "match": {
                                                "properties.value": "yes"
                                            }
                                        }
                                    ]
                                }
                            }
                        }
                    },
                    {
                        "match": {
                            "id": "1234"
                        }
                    }
                ]
            }
        },
        "script_fields": {
            "nested_scores": {
                "script": {
                    "lang": "painless",
                    "source": "for (int i = 0; i < params['_source']['performances'].length; ++i) { if(params['_source']['performances'][i]['key'] == params['customFields'][i]) { return params['_source']['performances'][i]['value'];}}return 0;",
                    "params": {
                        "customFields": ["performance1", "performance3", "performance5"]
                    }

                }
            }
        },
        "_source": [
            "id",
            "name",
            "name."
        ]
    }

Если я заменю "params ['customFields '] [i] "с простой строкой, она работает нормально, поэтому я предполагаю, что моя проблема где-то там, но не могу точно понять, что это такое.

С другой стороны, любая идея, как структурировать мой запрос так, чтобы результат безболезненного скрипта возвращался внутри "_source"?

В конце я хотел бы сделать что-то вроде этого:

"source": "for (int i = 0; i < params['_source']['performances'].length; ++i) {
                            for (int t = 0; t < params['customFields'].length; ++t) {
                                if(params['_source']['performances'][i]['key'] == params['customFields'][t]) {
                                    return params['_source']['performances'][i]['value']; 
                                }
                            }
                          }
                          return 0;"

Но сначала я хотел заставить его работать с приведенным выше кодом.

Я использую ES 6.4, если это имеет значение, и сначала я пытаюсь выполнить запрос, используя «elasticsearch-head» chrome plugin.

Однако результат выглядит примерно так (я изменил некоторые поля, такие как «kennzahlen» на «properties» для удобства в моем примере выше)

{
    "took": 679,
    "timed_out": false,
    "_shards": {
        "total": 5,
        "successful": 4,
        "skipped": 0,
        "failed": 1,
        "failures": [{
            "shard": 0,
            "index": "fsl_prd_products",
            "node": "xAUFwT0LRVeAuOktIr9gaA",
            "reason": {
                "type": "script_exception",
                "reason": "runtime error",
                "script_stack": [
                    "java.util.ArrayList.rangeCheck(ArrayList.java:653)",
                    "java.util.ArrayList.get(ArrayList.java:429)",
                    "if (params['_source']['kennzahlen'][i]['key'] == params['customFields'][i]) { ",
                    " ^---- HERE"
                ],
                "script": "for (int i = 0; i < params['_source']['kennzahlen'].length; ++i) { if (!params['_source'].containsKey('kennzahlen')) { return 0; } if (params['_source']['kennzahlen'][i]['key'] == params['customFields'][i]) { return params['_source']['kennzahlen'][i]['value']; } } return 0;",
                "lang": "painless",
                "caused_by": {
                    "type": "index_out_of_bounds_exception",
                    "reason": "Index: 3, Size: 3"
                }
            }
        }]
    },
    "hits": {
        "total": 1,
        "max_score": 0,
        "hits": []
    }
}

1 Ответ

0 голосов
/ 07 мая 2020

Результаты script_fields никогда не появятся в части _source ответа - они всегда разделены.

Давайте воспроизведем ваш вариант использования с помощью ES 7.2.0:

Настройка индекса + вставка (без пробелов для краткости)

PUT docs
{"mappings":{"properties":{"properties":{"type":"nested","properties":{"key":{"type":"text","fields":{"keyword":{"type":"keyword","ignore_above":256}}},"value":{"type":"text","fields":{"keyword":{"type":"keyword","ignore_above":256}}}}},"performances":{"properties":{"key":{"type":"text","fields":{"keyword":{"type":"keyword","ignore_above":256}}},"value":{"type":"double"}}},"name":{"type":"text","fields":{"keyword":{"type":"keyword","ignore_above":256}}},"id":{"type":"long"}}}}

POST docs/_doc
{"properties":[{"value":["D"],"key":"M"},{"value":["2019-12-31"],"key":"DOCUMENT_DATE"},{"isMultiValue":false,"value":["Yes"],"key":"ACTIVE_DOCUMENT"}],"performances":[{"value":123,"key":"performance1"},{"value":234,"key":"performance3"},{"value":345,"key":"performance5"},{"value":-456,"key":"someKey"},{"value":-567,"key":"someOtherKey"}],"name":"documentName43","id":"1234"}

затем поиск

GET docs/_search
{
  "query": {
    "bool": {
      "filter": [
        {
          "nested": {
            "path": "properties",
            "query": {
              "bool": {
                "filter": [
                  {
                    "match": {
                      "properties.key.keyword": "ACTIVE_DOCUMENT"
                    }
                  },
                  {
                    "match": {
                      "properties.value": "yes"
                    }
                  }
                ]
              }
            }
          }
        },
        {
          "match": {
            "id": "1234"
          }
        }
      ]
    }
  },
  "script_fields": {
    "nested_scores": {
      "script": {
        "lang": "painless",
        "source": """
          for (int i = 0; i < params['_source']['performances'].length; ++i) { 
            if (params['_source']['performances'][i]['key'] == params['customFields'][i]) { 
              return params['_source']['performances'][i]['value'];
            }

          }
          return 0;
        """,
        "params": {
          "customFields": [
            "performance1",
            "performance3",
            "performance5"
          ]
        }
      }
    }
  },
  "_source": [
    "id",
    "name",
    "name."
  ]
}

система выдаст

[
  {
    "_index":"docs",
    "_type":"_doc",
    "_id":"vOhj8HEBG_KW3EFn7wOf",
    "_score":0.0,
    "_source":{
      "name":"documentName43",
      "id":"1234"
    },
    "fields":{
      "nested_scores":[            <-------
        123
      ]
    }
  }
]

Если ваш запрос не работает, вы можете попробовать несколько проверок достоверности:

...
"source": """
          if (!params['_source'].containsKey('performances')) {
            return 0
          }
          // rest of the script
"""
...

Однако я не уверен, что вы пытаетесь сделать. Если условие в l oop выполнено, оно вернет первое совпадение. Таким образом, он может никогда не работать, например, до perf3 или perf5 ... Кроме того, _source.performances может не быть отсортирован, поэтому, наоборот, он может вернуть perf5 и выйти.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...