Агрегация ElasticSearch + сортировка по NonNumri c Поле 5.3 - PullRequest
1 голос
/ 05 марта 2020

Я хотел агрегировать данные в другом поле, а также хотел получить агрегированные данные отсортированным способом по имени.

Мои данные:

{
    "_index": "testing-aggregation",
    "_type": "employee",
    "_id": "emp001_local000000000000001",
    "_score": 10.0,
    "_source": {
        "name": [
            "Person 01"
        ],
        "groupbyid": [
            "group0001"
        ],
        "ranking": [
             "2.0"
        ]
    }
},
{
    "_index": "testing-aggregation",
    "_type": "employee",
    "_id": "emp002_local000000000000001",
    "_score": 85146.375,
    "_source": {
        "name": [
            "Person 02"
        ],
        "groupbyid": [
            "group0001"
        ],
        "ranking": [
             "10.0"
        ]
    }
},
{
    "_index": "testing-aggregation",
    "_type": "employee",
    "_id": "emp003_local000000000000001",
    "_score": 20.0,
    "_source": {
        "name": [
            "Person 03"
        ],
        "groupbyid": [
            "group0002"
        ],        
        "ranking": [
             "-1.0"
        ]
    }
},
{
    "_index": "testing-aggregation",
    "_type": "employee",
    "_id": "emp004_local000000000000001",
    "_score": 5.0,
    "_source": {
        "name": [
            "Person 04"
        ],
        "groupbyid": [
            "group0002"
        ],
        "ranking": [
             "2.0"
        ]
    }
}

Мой запрос :

{
    "size": 0,
    "query": {
        "bool": {
            "must": [
                {
                    "query_string": {
                        "query": "name:emp*^1000.0"
                    }
                }
            ]
        }
    },
    "aggs": {
        "groupbyid": {
            "terms": {
                "field": "groupbyid.raw",
                "order": {
                    "top_hit_agg": "desc"
                },
                "size": 10
            },
            "aggs": {
                "top_hit_agg": {
                    "terms": {
                        "field": "name"
                    }
                }
            }
        }
    }
}

Мое сопоставление:

{
    "name": {
        "type": "text",
        "fielddata": true,
        "fields": {
            "lower_case_sort": {
                "type": "text",
                "fielddata": true,
                "analyzer": "case_insensitive_sort"
            }
        }
    },
    "groupbyid": {
        "type": "text",
        "fielddata": true,
        "index": "analyzed",
        "fields": {
            "raw": {
                "type": "keyword",
                "index": "not_analyzed"
            }
        }
    }
}

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

Я хотел группировать по одному полю, а после этого сгруппированного сегмента я хочу сортировать по другому полю. Это примеры данных.

Существуют и другие поля, такие как созданный_, обновленный_он. Я также хотел получить отсортированные данные на основе этого поля. также получить данные по алфавиту.

Я хотел отсортировать данные по нечисловому типу данных c (строка). Я могу сделать тип данных нумерация c.

Я могу сделать это для поля ранжирования, но не могу сделать это для поля имени. Это давало ошибку ниже.

Expected numeric type on field [name], but got [text]; 

1 Ответ

1 голос
/ 06 марта 2020

Вы просите несколько вещей, поэтому я постараюсь ответить на них по очереди.

Шаг 1. Сортировка сегментов по релевантности

Я получаю данные на основе в среднем по релевантности сгруппированных записей.

Если это то, что вы пытаетесь сделать, это не то, что делает агрегат, который вы написали. Термины агрегации по умолчанию сортируют сегменты по количеству документов в каждом сегменте по убыванию. Чтобы отсортировать группы по «средней релевантности» (которую я буду интерпретировать как «среднее _score документов в группе»), вам нужно добавить субагрегацию в балл и отсортировать агрегацию терминов следующим образом:

"aggregations": {
  "most_relevant_groups": {
    "terms": {
      "field": "groupbyid.raw",
      "order": {
        "average_score": "desc"
      }
    },
    "aggs": {
      "average_score": {
        "avg": {
          "script": {
            "inline": "_score",
            "lang": "painless",
          }
        }
      }
    }
  }
}

Шаг 2: Сортировка сотрудников по имени

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

Чтобы отсортировать документы в каждом сегменте, вы можете использовать агрегирование top_hits:

"aggregations": {
  "most_relevant_groups": {
    "terms": {
      "field": "groupbyid.raw",
      "order": {
        "average_score": "desc"
      }
    },
    "aggs": {
      "employees": {
        "top_hits": {
          "size": 10,  // Default will be 10 - change to whatever
          "sort": [
            {
              "name.lower_case_sort": {
                "order": "asc"
              }
            }
          ]
        }
      }
    }
  }
}

Шаг 3: Объединить все вместе

Собрав оба вышеперечисленных вместе, следующая агрегация должна соответствовать вашим потребностям (обратите внимание, что я использовал запрос function_score для имитации «релевантности», основанной на ранжировании - ваш запрос может быть любым и просто должен быть любым запросом, который дает вам любую релевантность нужно):

POST /testing-aggregation/employee/_search
{
  "size": 0,
  "query": {
    "function_score": {
      "functions": [
        {
          "field_value_factor": {
            "field": "ranking"
          }
        }
      ]
    }
  },
  "aggs": {
    "groupbyid": {
      "terms": {
        "field": "groupbyid.raw",
        "size": 10,
        "order": {
          "average_score": "desc"
        }
      },
      "aggs": {
        "average_score": {
          "avg": {
            "script": {
              "inline": "_score",
              "lang": "painless"
            }
          }
        },
        "employees": {
          "top_hits": {
            "size": 10,
            "sort": [
              {
                "name.lower_case_sort": {
                  "order": "asc"
                }
              }
            ]
          }
        }
      }
    }
  }
}
...