Spec-Zone.ru › Elasticsearch 8
›Elasticsearch Guide [8.17] ›Агрегации ›Агрегации метрик

Агрегация Cardinality

Агрегация метрик, которая рассчитывает приблизительное количество уникальных значений.

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

resp = client.search(
    index="sales",
    size="0",
    aggs={
        "type_count": {
            "cardinality": {
                "field": "type"
            }
        }
    },
)
print(resp)
response = client.search(
  index: 'sales',
  size: 0,
  body: {
    aggregations: {
      type_count: {
        cardinality: {
          field: 'type'
        }
      }
    }
  }
)
puts response
const response = await client.search({
  index: "sales",
  size: 0,
  aggs: {
    type_count: {
      cardinality: {
        field: "type",
      },
    },
  },
});
console.log(response);
POST /sales/_search?size=0
{
  "aggs": {
    "type_count": {
      "cardinality": {
        "field": "type"
      }
    }
  }
}

Ответ:

{
  ...
  "aggregations": {
    "type_count": {
      "value": 3
    }
  }
}

Управление точностью

Эта агрегация также поддерживает опцию precision_threshold:

resp = client.search(
    index="sales",
    size="0",
    aggs={
        "type_count": {
            "cardinality": {
                "field": "type",
                "precision_threshold": 100
            }
        }
    },
)
print(resp)
response = client.search(
  index: 'sales',
  size: 0,
  body: {
    aggregations: {
      type_count: {
        cardinality: {
          field: 'type',
          precision_threshold: 100
        }
      }
    }
  }
)
puts response
const response = await client.search({
  index: "sales",
  size: 0,
  aggs: {
    type_count: {
      cardinality: {
        field: "type",
        precision_threshold: 100,
      },
    },
  },
});
console.log(response);
POST /sales/_search?size=0
{
  "aggs": {
    "type_count": {
      "cardinality": {
        "field": "type",
        "precision_threshold": 100 
      }
    }
  }
}

Опции precision_threshold позволяют пожертвовать точностью ради экономии памяти, и определяет количество уникальных значений, ниже которого подсчеты ожидаются точными. Выше этого значения подсчеты могут стать несколько менее точными. Максимальное поддерживаемое значение равно 40000, пороги выше этого значения будут иметь тот же эффект, что и порог 40000. Значение по умолчанию равно 3000.

Значения подсчета приблизительные

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

Эта агрегация cardinality основана на алгоритме HyperLogLog++, который подсчитывает значения на основе хешей с интересными свойствами:

  • настраиваемая точность, которая определяет компромисс между памятью и точностью,
  • высокая точность для множеств низкой кратности,
  • фиксированное использование памяти: независимо от того, есть ли десятки или миллиарды уникальных значений, использование памяти зависит только от заданной точности.

Для порога точности c используемая реализация требует около c * 8 байт.

На следующей диаграмме показано, как ошибка меняется до и после порога:

cardinality error

Для всех трех порогов подсчеты были точными до заданного порога. Хотя это не гарантируется, это, вероятно, так. Точность на практике зависит от набора данных. В целом, большинство наборов данных демонстрируют последовательно высокую точность. Также обратите внимание, что даже с порогом в 100 ошибка остается очень низкой (1-6%, как видно на графике выше), даже при подсчете миллионов элементов.

Алгоритм HyperLogLog++ зависит от ведущих нулей хешированных значений, точные распределения хешей в наборе данных могут влиять на точность подсчета количества уникальных значений.

Предварительно вычисленные хеши

Для строковых полей с высокой кратностью может быть быстрее сохранить хеш значений поля в индексе, а затем выполнить агрегацию cardinality на этом поле. Это можно сделать, предоставив хеши со стороны клиента или позволив Elasticsearch вычислить хеши для вас, используя плагин mapper-murmur3.

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

Скрипт

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

resp = client.search(
    index="sales",
    size="0",
    runtime_mappings={
        "type_and_promoted": {
            "type": "keyword",
            "script": "emit(doc['type'].value + ' ' + doc['promoted'].value)"
        }
    },
    aggs={
        "type_promoted_count": {
            "cardinality": {
                "field": "type_and_promoted"
            }
        }
    },
)
print(resp)
response = client.search(
  index: 'sales',
  size: 0,
  body: {
    runtime_mappings: {
      type_and_promoted: {
        type: 'keyword',
        script: "emit(doc['type'].value + ' ' + doc['promoted'].value)"
      }
    },
    aggregations: {
      type_promoted_count: {
        cardinality: {
          field: 'type_and_promoted'
        }
      }
    }
  }
)
puts response
const response = await client.search({
  index: "sales",
  size: 0,
  runtime_mappings: {
    type_and_promoted: {
      type: "keyword",
      script: "emit(doc['type'].value + ' ' + doc['promoted'].value)",
    },
  },
  aggs: {
    type_promoted_count: {
      cardinality: {
        field: "type_and_promoted",
      },
    },
  },
});
console.log(response);
POST /sales/_search?size=0
{
  "runtime_mappings": {
    "type_and_promoted": {
      "type": "keyword",
      "script": "emit(doc['type'].value + ' ' + doc['promoted'].value)"
    }
  },
  "aggs": {
    "type_promoted_count": {
      "cardinality": {
        "field": "type_and_promoted"
      }
    }
  }
}

Отсутствующее значение

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

resp = client.search(
    index="sales",
    size="0",
    aggs={
        "tag_cardinality": {
            "cardinality": {
                "field": "tag",
                "missing": "N/A"
            }
        }
    },
)
print(resp)
response = client.search(
  index: 'sales',
  size: 0,
  body: {
    aggregations: {
      tag_cardinality: {
        cardinality: {
          field: 'tag',
          missing: 'N/A'
        }
      }
    }
  }
)
puts response
const response = await client.search({
  index: "sales",
  size: 0,
  aggs: {
    tag_cardinality: {
      cardinality: {
        field: "tag",
        missing: "N/A",
      },
    },
  },
});
console.log(response);
POST /sales/_search?size=0
{
  "aggs": {
    "tag_cardinality": {
      "cardinality": {
        "field": "tag",
        "missing": "N/A" 
      }
    }
  }
}

Документы без значения в поле tag попадут в ту же корзину, что и документы со значением N/A.

Подсказка выполнения

Вы можете выполнять агрегации cardinality с помощью различных механизмов:

  • используя значения поля напрямую (direct)
  • используя глобальные порядковые номера поля и разрешая эти значения после завершения фрагмента (global_ordinals)
  • используя порядковые номера сегмента и разрешая их значения после каждого сегмента (segment_ordinals)

Кроме того, есть два режима «на основе эвристики». Эти режимы заставят Elasticsearch использовать некоторые данные о состоянии индекса для выбора подходящего метода выполнения.

  • save_time_heuristic - это значение по умолчанию в Elasticsearch 8.4 и более поздних версиях.
  • save_memory_heuristic - это значение по умолчанию в Elasticsearch 8.3 и более ранних версиях.

Если не указано иное, Elasticsearch применит эвристику для выбора подходящего режима. Также обратите внимание, что для некоторых данных (не порядковых полей) direct является единственным вариантом, и подсказка будет проигнорирована в этих случаях. Как правило, не нужно устанавливать это значение.

© 2023-2025 Elasticsearch
As of September 2024, Elasticsearch is available under a choice of three licenses: the Server Side Public License (SSPL), the Elastic License, or the AGPLv3 (OSI approved).
Elasticsearch and the Elasticsearch logo are trademarks of Elasticsearch B.V., registered in the U.S. and in other countries.
https://www.elastic.co/guide/en/elasticsearch/reference/8.17/search-aggregations-metrics-cardinality-aggregation.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API