web-dev-qa-db-ja.com

ElasticSearchの痛みのないスクリプト:ネストされたオブジェクトの配列を反復処理する方法

_script_score_の_function_score_を使用してスクリプトを作成しようとしています。 rankingsフィールドが_type="nested"_であるドキュメントがいくつかあります。フィールドのマッピングは次のとおりです。

_"rankings": {
        "type": "nested",
        "properties": {
          "rank1": {
            "type": "long"
          },
          "rank2": {
            "type": "float"
          },
          "subject": {
            "type": "text"
          }
        }
      }
_

サンプル文書は次のとおりです。

_"rankings": [
{
    "rank1": 1051,
    "rank2": 78.5,
    "subject": "s1"
},
{
    "rank1": 45,
    "rank2": 34.7,
    "subject": "s2"
}]
_

私が達成したいのは、ランキングのネストされたオブジェクトを反復処理することです。実際、特定のsubjectを見つけて_rank1, rank2_を使用して何かを計算するには、forループを使用する必要があります。これまでのところ、私はこのようなものを使用していますが、動作していないようです(コンパイルエラーをスロー):

_"function_score": {
"script_score": {
    "script": {
        "lang": "painless",
        "inline": 
                 "sum = 0;"
                 "for (item in doc['rankings_cug']) {"
                     "sum = sum + doc['rankings_cug.rank1'].value;"
                 "}"
         }
    }
}
_

また、次のオプションを試しました。

  1. forの代わりに_:_を使用するinループ:for (item:doc['rankings'])は成功しません。
  2. forinを使用してループしますが、オブジェクトの特定の要素、つまり_rank1_:for (item in doc['rankings.rank1'].values)を反復処理しようとしますが、実際にはコンパイルされますが、 _rank1_の長さゼロの配列を見つけます。

__source_要素はJSONに似たオブジェクトを返すことができる要素であると読みましたが、検索クエリではサポートされていないことがわかりました。

それを進める方法のアイデアを教えてください。

どうもありがとう。

12
christinabo

params._source経由で_sourceにアクセスできます。これは動作します:

PUT /rankings/result/1?refresh
{
  "rankings": [
    {
      "rank1": 1051,
      "rank2": 78.5,
      "subject": "s1"
    },
    {
      "rank1": 45,
      "rank2": 34.7,
      "subject": "s2"
    }
  ]
}

POST rankings/_search

POST rankings/_search
{
  "query": {
    "match": {
      "_id": "1"
    }
  },
  "script_fields": {
    "script_score": {
      "script": {
        "lang": "painless",
        "inline": "double sum = 0.0; for (item in params._source.rankings) { sum += item.rank2; } return sum;"
      }
    }
  }
}

DELETE rankings
12
Rahul Singhai

残念ながら、ElasticSearchスクリプティングは一般に、この方法でネストされたドキュメントにアクセスする機能をサポートしていません(ペインレスを含む)。おそらく、ランキングを複数値のフィールドに格納するマッピングとは異なる構造を考えてください。このような方法でランキングを反復処理する必要がある場合です。最終的に、ネストされたデータは、ここで説明する方法でスコアを取得できるように、非正規化して親ドキュメントに入れる必要があります。

6
jdconrad

配列内のネストされたオブジェクトの場合、アイテムを繰り返し処理しました。次に、elasticsearchインデックスのサンプルデータを示します。

{
  "_index": "activity_index",
  "_type": "log",
  "_id": "AVjx0UTvgHp45Y_tQP6z",
  "_version": 4,
  "found": true,
  "_source": {
    "updated": "2016-12-11T22:56:13.548641",
    "task_log": [
      {
        "week_end_date": "2016-12-11",
        "log_hours": 16,
        "week_start_date": "2016-12-05"
      },
      {
        "week_start_date": "2016-03-21",
        "log_hours": 0,
        "week_end_date": "2016-03-27"
      },
      {
        "week_start_date": "2016-04-24",
        "log_hours": 0,
        "week_end_date": "2016-04-30"
      }
    ],
    "created": "2016-12-11T22:56:13.548635",
    "userid": 895,
    "misc": {

    },
    "current": false,
    "taskid": 1023829
  }
}

ネストされたオブジェクトを反復処理する「痛みのない」スクリプトを次に示します。

{
  "script": {
    "lang": "painless",
    "inline": 
        "boolean contains(def x, def y) {
          for (item in x) {
            if (item['week_start_date'] == y){
              return true
            }
          }
          return false 
         }
         if(!contains(ctx._source.task_log, params.start_time_param) {
           ctx._source.task_log.add(params.week_object)
         }",
         "params": {
            "start_time_param": "2016-04-24",
             "week_object": {
               "week_start_date": "2016-04-24",
               "week_end_date": "2016-04-30",
               "log_hours": 0
              }
          }
  }
}

上記の更新用スクリプトを使用:/ activity_index/log/AVjx0UTvgHp45Y_tQP6z/_updateスクリプトで、2つの引数を持つ「含む」という関数を作成しました。関数を呼び出しました。古いgroovyスタイル:ctx._source.task_log.contains()は、ES 5.Xがネストされたオブジェクトを別のドキュメントに保存するため、機能しません。これがお役に立てば幸いです!

4
Priyesh