ElasticSearch: возможно ли выполнить «взвешенную среднюю агрегацию», взвешенную по баллу? - PullRequest
1 голос
/ 27 апреля 2020

Я пытаюсь выполнить среднюю над полем цены (price.avg). Но я хочу, чтобы лучшие совпадения запроса оказывали большее влияние на среднее значение, чем последние, поэтому среднее значение должно быть взвешено с помощью поля рассчитанного балла. Это агрегат, который я реализую.

{
    "query": {...},
    "size": 100,
    "aggs": {
        "weighted_avg_price": {
            "weighted_avg": {
                "value": {
                    "field": "price.avg"
                },
                "weight": {
                    "script": "_score"
                }
            }
        }
    }
}

Это должно дать мне то, что я хочу. Но вместо этого я получаю нулевое значение:

{...
    "hits": {...},
    "aggregations": {
        "weighted_avg_price": {
            "value": null
        }
    }
}

Я что-то упускаю? Возможен ли этот запрос агрегации? Есть ли обходной путь?

Ответы [ 2 ]

1 голос
/ 27 апреля 2020

Когда вы отлаживаете то, что доступно из script

GET prices/_search
{
  "size": 0,
  "aggs": {
    "weighted_avg_price": {
      "weighted_avg": {
        "value": {
          "field": "price"
        },
        "weight": {
          "script": "Debug.explain(new ArrayList(params.keySet()))"
        }
      }
    }
  }
}

, выдается следующее:

[doc, _source, _doc, _fields]

Ни один из них не содержит информацию о запросе _score, который вы пытаемся получить доступ, потому что агрегаты работают в контексте, отдельном от оценки на уровне запросов. Это означает, что для значения weight необходимо либо

  • , существующее в do c, либо
  • , существующее в do c + be , изменяемое , либо
  • будет постоянной времени запроса (например, 42 или 0.1)

В качестве обходного пути можно применить математическую функцию к извлеченным price, например

"script": "Math.pow(doc.price.value, 0.5)"

0 голосов
/ 28 апреля 2020

@ jzzfs Я пытаюсь с подходом "avg первых N результатов (упорядоченных _score)", используя агрегация по числу попаданий :

{
    "query": {
        "bool": {
            "should": [
                ...
            ],
            "minimum_should_match": 0
        }
    },
    "size": 0,
    "from": 0,
    "sort": [
        {
            "_score": {
                "order": "desc"
            }
        }
    ],
    "aggs": {
        "top_avg_price": {
            "avg": {
                "field": "price.max"
            }
        },
        "aggs": {
            "top_hits": {
                "size": 10, // N: Changing the number of results doesn't change the top_avg_price 
                "_source": {
                    "includes": [
                        "price.max"
                    ]
                }
            }
        }
    },
    "explain": "false"
}

агрегация avg делается по основным результатам, а не по top_hits. Я думаю, что top_avg_rpice должно быть подгруппой top_hits. Но я думаю, что это невозможно банкомат.

...