#elasticsearch #elasticsearch-5 #elasticsearch-aggregation #elasticsearch-dsl
#elasticsearch #elasticsearch-5 #elasticsearch-агрегация #elasticsearch-dsl
Вопрос:
У меня есть следующие данные в elasticsearch
{
"_index": "media",
"_type": "information",
"_id": "6838",
"_source": {
"demographics_countries": {
"AE": 0.17543859649122806,
"CA": 0.013157894736842105,
"FR": 0.017543859649122806,
"GB": 0.043859649122807015,
"IT": 0.02631578947368421,
"LB": 0.013157894736842105,
"SA": 0.49122807017543857,
"TR": 0.017543859649122806,
"US": 0.09210526315789472
}
}
},
{
"_index": "media",
"_type": "information",
"_id": "57696",
"_source": {
"demographics_countries": {
"TN": 0.8125,
"MA": 0.034375,
"DZ": 0.032812,
"FR": 0.0125,
"EG": 0.0125,
"IN": 0.009375,
"SA": 0.009375
}
}
]
Ожидаемый результат:
Найдите документ, в котором определенная страна SA
(Саудовская Аравия) входит в топ-3 в demographics_countries
Например:
«_id»: «6838» (первый документ) соответствует, потому SA
что (Саудовская Аравия) входит в топ demographics_countries
-3 в вышеупомянутом примере документа.
Пробовал ?: Я пытался фильтровать с помощью top_hits, но это работает не так, как ожидалось.
Любое предложение будет благодарно
Комментарии:
1. Совершенно непонятно, чего вы пытаетесь здесь добиться. Какова ваша логика и что вы пытаетесь извлечь?
2. @Evaldas Buinauskas Спасибо. Имея документ в социальных сетях со списком демографических стран, мы должны выяснить, что конкретная страна входит в топ-3 в каждом документе. Например, конкретная страна указана как «SA», что является коротким кодом для Саудовской Аравии. Пожалуйста, дайте мне знать, если что-то нужно уточнить
Ответ №1:
С текущей моделью данных это довольно сложно сделать. То, что я бы предложил, может быть не самым простым способом сделать это, но в конечном итоге это определенно будет самый быстрый запрос.
Я бы посоветовал переделать ваши документы, чтобы они уже включали лучшие страны:
[
{
"_index": "media",
"_type": "information",
"_id": "6838",
"_source": {
"top_demographics_countries": ["TN", "MA", "DZ"],
"demographics_countries": {
"AE": 0.17543859649122806,
"CA": 0.013157894736842105,
"FR": 0.017543859649122806,
"GB": 0.043859649122807015,
"IT": 0.02631578947368421,
"LB": 0.013157894736842105,
"SA": 0.49122807017543857,
"TR": 0.017543859649122806,
"US": 0.09210526315789472
}
}
},
{
"_index": "media",
"_type": "information",
"_id": "57696",
"_source": {
"top_demographics_countries": ["TN", "MA", "DZ"],
"demographics_countries": {
"TN": 0.8125,
"MA": 0.034375,
"DZ": 0.032812,
"FR": 0.0125,
"EG": 0.0125,
"IN": 0.009375,
"SA": 0.009375
}
}
}
]
Игнорируйте значения, которые я выбрал top_demographics_countries
. При таком подходе вы всегда можете предварительно вычислить top, а затем использовать простой запрос терминов, чтобы проверить, содержит ли документ это значение или нет:
{
"query": {
"bool": {
"filter": {
"term": {
"top_demographics_countries": "SA"
}
}
}
}
}
Будет дешевле вычислять их один раз во время сохранения по сравнению с постоянным динамическим построением этого предложения.
Ответ №2:
@Evaldas прав — лучше заранее извлечь топ-3.
Но если вы ничего не можете с собой поделать и чувствуете себя вынужденным использовать java / безболезненно, вот один из подходов:
{
"query": {
"bool": {
"must": [
{
"exists": {
"field": "demographics_countries.SA"
}
},
{
"script": {
"script": {
"source": """
def tuple_list = new ArrayList();
for (def c : params.all_countries) {
def key = 'demographics_countries.' c;
if (!doc.containsKey(key) || doc[key].size() == 0) {
continue;
}
def val = doc[key].value;
tuple_list.add([c, val]);
}
// sort tuple list by the country values
Collections.sort(tuple_list, (arr1, arr2) -> arr1[1] < arr2[1] ? 1 : -1);
// slice amp; take only the top 3
def top_3_countries = tuple_list.subList(0, 3).stream().map(arr -> arr[0]).collect(Collectors.toList());
return top_3_countries.size() >=3 amp;amp; top_3_countries.contains(params.country_of_interest);
""",
"params": {
"country_of_interest": "SA",
"all_countries": [
"AE",
"CA",
"FR",
"GB",
"IT",
"LB",
"SA",
"TR",
"US",
"TN",
"MA",
"DZ",
"EG",
"IN"
]
}
}
}
}
]
}
}
}