Объединение нескольких ключей в ElasticSearch - PullRequest
0 голосов
/ 26 ноября 2018

Я новичок в Elastic Search и изучал запрос агрегации.У меня есть документы в формате -

{"name":"A",
     "class":"10th",
     "subjects":{
         "S1":92,
         "S2":92,
         "S3":92,
     }
}

У нас в ES есть около 40 тыс. Таких документов с разными предметами от ученика к ученику.Запрос к системе может заключаться в агрегировании всех предметных оценок для данного класса.Мы попытались создать запрос агрегации сегментов, как описано в этом руководстве здесь , однако при этом создается один фрагмент на документ, и в нашем понимании требуется явное упоминание каждого предмета.

Мы хотим, чтобы система генерировала тематические агрегированные данные для данных, выполняя один запрос агрегации. Проблема, с которой я сталкиваюсь, заключается в том, что в наших данных предмет может варьироваться от студента к студенту, и у нас нет глобальногосписок предметных ключей.

Мы написали следующий сценарий, но он работает, только если мы знаем все возможные предметы.

GET student_data_v1_1 / _search

{ "query" :
    {"match" : 
         { "class" : "' + query + '" }}, 
         "aggs" : { "my_buckets" : { "terms" : 
         { "field" : "subjects", "size":10000 },
         "aggregations": {"the_avg": 
                      {"avg": { "field": "subjects.value" }}} }},
          "size" : 0 }'

, но этот запрос работает только для структуры документа, но не работает, если определены несколько предметов, где мы можем не знать пару ключей -

{"name":"A",
     "class":"10th",
     "subjects":{
         "value":93
     }
}

Альтернативная форма представления документа заключается в том, что предметом является список словарей -

    {"name":"A",
     "class":"10th",
     "subjects":[
         {"S1":92},
         {"S2":92},
         {"S3":92},
     ]
}

Было бы полезно иметь запрос агрегации для решения любого из двух форматов документа.
====== РЕДАКТИРОВАТЬ ======

После обновления документа для хранения весов для каждого предмета -

        {
class": "10th",
   "subject": [
 {
   "name": "s1",
   "marks": 90,
   "weight":30
 },
 {
   "name": "s2",
  "marks": 80,
   "weight":70
 }
   ]}

Я обновил запрос, чтобы-

{
  "query": {
    "match": {
      "class": "10th"
}
  },
  "aggs": {
    "subjects": {
      "nested": {
        "path": "scores"
      },    
      "aggs": {
        "subjects": {
          "terms": {
            "field": "subject.name"
      },
      "aggs" : { "weighted_grade": { "weighted_avg": { "value": { "field": "subjects.score" }, "weight": { "field": "subjects.weight" } } } }
      }
    }
  }
}
      },
      "size": 0
    }

но выдает ошибку-

{u'error': {u'col': 312,
u'line': 1,
u'reason': u'Unknown BaseAggregationBuilder [weighted_avg]',
u'root_cause': [{u'col': 312,
u'line': 1,
u'reason': u'Unknown BaseAggregationBuilder [weighted_avg]',
u'type': u'unknown_named_object_exception'}],
u'type': u'unknown_named_object_exception'},
u'status': 400}

1 Ответ

0 голосов
/ 27 ноября 2018

Для достижения требуемого результата я бы предложил вам сохранить отображение индекса следующим образом:

{
  "properties": {
    "class": {
      "type": "keyword"
    },
    "subject": {
      "type": "nested",
      "properties": {
        "marks": {
          "type": "integer"
        },
        "name": {
          "type": "keyword"
        }
      }
    }
  }
}

В приведенном выше отображении я создал subject как nested тип с двумя свойствами, name для хранения имени субъекта и marks для хранения меток в теме.

Пример документа :

{
  "class": "10th",
  "subject": [
    {
      "name": "s1",
      "marks": 90
    },
    {
      "name": "s2",
      "marks": 80
    }
  ]
}

Теперь вы можете использовать вложенное агрегирование и многоуровневая агрегация (т.е. агрегация внутри агрегации).Я использовал вложенную агрегацию с агрегацией terms для subject.name, чтобы получить корзину, содержащую все доступные предметы.Затем, чтобы получить среднее значение для каждого предмета, мы добавляем дочернюю агрегацию avg к агрегации subjects, как показано ниже:

{
  "query": {
    "match": {
      "class": "10th"
    }
  },
  "aggs": {
    "subjects": {
      "nested": {
        "path": "subject"
      },
      "aggs": {
        "subjects": {
          "terms": {
            "field": "subject.name"
          },
          "aggs": {
            "avg_score": {
              "avg": {
                "field": "subject.marks"
              }
            }
          }
        }
      }
    }
  },
  "size": 0
}

ПРИМЕЧАНИЕ: я добавил "size" : 0, чтобы упругая неt вернуть соответствующие документы в результате.Включение или исключение полностью зависит от вашего варианта использования.

Пример выборки :

{
  "took": 25,
  "timed_out": false,
  "_shards": {
    "total": 1,
    "successful": 1,
    "skipped": 0,
    "failed": 0
  },
  "hits": {
    "total": 3,
    "max_score": 0,
    "hits": [

    ]
  },
  "aggregations": {
    "subjects": {
      "doc_count": 6,
      "subjects": {
        "doc_count_error_upper_bound": 0,
        "sum_other_doc_count": 0,
        "buckets": [
          {
            "key": "s1",
            "doc_count": 3,
            "avg_score": {
              "value": 80
            }
          },
          {
            "key": "s2",
            "doc_count": 2,
            "avg_score": {
              "value": 75
            }
          },
          {
            "key": "s3",
            "doc_count": 1,
            "avg_score": {
              "value": 80
            }
          }
        ]
      }
    }
  }
}

Как видно, результат содержит сегменты с key в качестве имени субъекта и avg_score.value в качестве средней оценки.

ОБНОВЛЕНИЕ для включения weighted_avg:

{
  "query": {
    "match": {
      "class": "10th"
    }
  },
  "aggs": {
    "subjects": {
      "nested": {
        "path": "subject"
      },
      "aggs": {
        "subjects": {
          "terms": {
            "field": "subject.name"
          },
          "aggs": {
            "avg_score": {
              "avg": {
                "field": "subject.marks"
              }
            },
            "weighted_grade": {
              "weighted_avg": {
                "value": {
                  "field": "subject.marks"
                },
                "weight": {
                  "field": "subject.weight"
                }
              }
            }
          }
        }
      }
    }
  },
  "size": 0
}
...