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

Агрегация значимых текстов

Агрегация, возвращающая интересные или необычные вхождения свободных текстовых терминов в наборе. Она похожа на агрегацию значимых терминов, но отличается тем, что:

  • Она специально предназначена для использования с полями типа text
  • Она не требует данных поля или doc-значений
  • Она повторно анализирует текстовое содержимое в режиме реального времени, что означает, что она также может отфильтровать повторяющиеся фрагменты шумного текста, которые иначе искажают статистику.

Повторный анализ больших наборов результатов потребует много времени и памяти. Рекомендуется использовать агрегацию significant_text в качестве дочерней агрегации либо sampler, либо diversified sampler для ограничения анализа малым выбором документов с наилучшим соответствием, например, 200. Это обычно улучшит скорость, использование памяти и качество результатов.

Примеры использования:

  • Предложение "H5N1" при поиске пользователей по запросу "птичий грипп", чтобы расширить запросы
  • Предложение ключевых слов, относящихся к символу биржевого тикера $ATI, для использования в автоматизированном классификаторе новостей

В этих случаях выбираемые слова — не просто самые популярные термины в результатах. Самые популярные слова обычно довольно скучны (и, из, в, мы, я, они …). Значимые слова — это те, которые претерпели значительные изменения в популярности, измеренные между фоновым и фоновым наборами. Если термин "H5N1" встречается только в 5 документах в индексе из 10 миллионов документов, а затем он найден в 4 из 100 документов, составляющих результаты поиска пользователя, это значимо и, вероятно, очень актуально для его поиска. 5/10 000 000 против 4/100 — это большой скачок частоты.

Базовое использование

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

Пример:

resp = client.search(
    index="news",
    query={
        "match": {
            "content": "Bird flu"
        }
    },
    aggregations={
        "my_sample": {
            "sampler": {
                "shard_size": 100
            },
            "aggregations": {
                "keywords": {
                    "significant_text": {
                        "field": "content"
                    }
                }
            }
        }
    },
)
print(resp)
response = client.search(
  index: 'news',
  body: {
    query: {
      match: {
        content: 'Bird flu'
      }
    },
    aggregations: {
      my_sample: {
        sampler: {
          shard_size: 100
        },
        aggregations: {
          keywords: {
            significant_text: {
              field: 'content'
            }
          }
        }
      }
    }
  }
)
puts response
const response = await client.search({
  index: "news",
  query: {
    match: {
      content: "Bird flu",
    },
  },
  aggregations: {
    my_sample: {
      sampler: {
        shard_size: 100,
      },
      aggregations: {
        keywords: {
          significant_text: {
            field: "content",
          },
        },
      },
    },
  },
});
console.log(response);
GET news/_search
{
  "query": {
    "match": { "content": "Bird flu" }
  },
  "aggregations": {
    "my_sample": {
      "sampler": {
        "shard_size": 100
      },
      "aggregations": {
        "keywords": {
          "significant_text": { "field": "content" }
        }
      }
    }
  }
}

Ответ:

{
  "took": 9,
  "timed_out": false,
  "_shards": ...,
  "hits": ...,
    "aggregations" : {
        "my_sample": {
            "doc_count": 100,
            "keywords" : {
                "doc_count": 100,
                "buckets" : [
                    {
                        "key": "h5n1",
                        "doc_count": 4,
                        "score": 4.71235374214817,
                        "bg_count": 5
                    }
                    ...
                ]
            }
        }
    }
}

Результаты показывают, что «h5n1» — это один из нескольких терминов, тесно связанных с птичьим гриппом. Он встречается всего 5 раз в нашем индексе в целом (см. bg_count), и тем не менее 4 из них повезло появиться в нашей выборке из 100 документов по запросу «птичий грипп». Это предполагает значимое слово, которое пользователь может потенциально добавить в свой запрос.

Работа с шумными данными, используя filter_duplicate_text

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

В данных реального мира эти повторяющиеся фрагменты текста часто встречаются в результатах significant_text, если они не отфильтрованы. Фильтрация почти дублирующего текста — сложная задача на этапе индексирования, но мы можем очистить данные в режиме реального времени во время запроса, используя параметр filter_duplicate_text.

Сначала давайте рассмотрим неотфильтрованный пример из реального мира, используя набор данных Signal media из миллиона новостных статей, охватывающих широкий спектр новостей. Вот сырые результаты агрегации значительного текста для поиска статей, упоминающих «elasticsearch»:

{
  ...
  "aggregations": {
    "sample": {
      "doc_count": 35,
      "keywords": {
        "doc_count": 35,
        "buckets": [
          {
            "key": "elasticsearch",
            "doc_count": 35,
            "score": 28570.428571428572,
            "bg_count": 35
          },
          ...
          {
            "key": "currensee",
            "doc_count": 8,
            "score": 6530.383673469388,
            "bg_count": 8
          },
          ...
          {
            "key": "pozmantier",
            "doc_count": 4,
            "score": 3265.191836734694,
            "bg_count": 4
          },
          ...

}

Неочищенные документы выявили некоторые странные термины, которые, судя по всему, статистически коррелируют с появлением нашего поискового термина «elasticsearch», например, «pozmantier». Мы можем углубиться в примеры этих документов, чтобы понять, почему pozmantier связан с этим запросом:

resp = client.search(
    index="news",
    query={
        "simple_query_string": {
            "query": "+elasticsearch  +pozmantier"
        }
    },
    source=[
        "title",
        "source"
    ],
    highlight={
        "fields": {
            "content": {}
        }
    },
)
print(resp)
response = client.search(
  index: 'news',
  body: {
    query: {
      simple_query_string: {
        query: '+elasticsearch  +pozmantier'
      }
    },
    _source: [
      'title',
      'source'
    ],
    highlight: {
      fields: {
        content: {}
      }
    }
  }
)
puts response
const response = await client.search({
  index: "news",
  query: {
    simple_query_string: {
      query: "+elasticsearch  +pozmantier",
    },
  },
  _source: ["title", "source"],
  highlight: {
    fields: {
      content: {},
    },
  },
});
console.log(response);
GET news/_search
{
  "query": {
    "simple_query_string": {
      "query": "+elasticsearch  +pozmantier"
    }
  },
  "_source": [
    "title",
    "source"
  ],
  "highlight": {
    "fields": {
      "content": {}
    }
  }
}

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

{
  ...
  "hits": {
    "hits": [
      {
        ...
        "_source": {
          "source": "Presentation Master",
          "title": "T.E.N. Announces Nominees for the 2015 ISE® North America Awards"
        },
        "highlight": {
          "content": [
            "City of San Diego Mike <em>Pozmantier</em>, Program Manager, Cyber Security Division, Department of",
            " Janus, Janus <em>ElasticSearch</em> Security Visualization Engine "
          ]
        }
      },
      {
        ...
        "_source": {
          "source": "RCL Advisors",
          "title": "T.E.N. Announces Nominees for the 2015 ISE(R) North America Awards"
        },
        "highlight": {
          "content": [
            "Mike <em>Pozmantier</em>, Program Manager, Cyber Security Division, Department of Homeland Security S&T",
            "Janus, Janus <em>ElasticSearch</em> Security Visualization Engine"
          ]
        }
      },
      ...

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

Как обычно, этот пространный пресс-релиз был скопирован и вставлен в различные новостные сайты, и в результате любые редкие имена, номера или опечатки в них статистически коррелируют с нашим соответствующим запросом.

К счастью, похожие документы, как правило, имеют сходные ранги, поэтому в рамках изучения потока документов с наилучшим соответствием агрегация significant_text может применять фильтр для удаления последовательностей из 6 или более токенов, которые уже были замечены. Давайте попробуем этот же запрос, но с включенным параметром filter_duplicate_text:

resp = client.search(
    index="news",
    query={
        "match": {
            "content": "elasticsearch"
        }
    },
    aggs={
        "sample": {
            "sampler": {
                "shard_size": 100
            },
            "aggs": {
                "keywords": {
                    "significant_text": {
                        "field": "content",
                        "filter_duplicate_text": True
                    }
                }
            }
        }
    },
)
print(resp)
response = client.search(
  index: 'news',
  body: {
    query: {
      match: {
        content: 'elasticsearch'
      }
    },
    aggregations: {
      sample: {
        sampler: {
          shard_size: 100
        },
        aggregations: {
          keywords: {
            significant_text: {
              field: 'content',
              filter_duplicate_text: true
            }
          }
        }
      }
    }
  }
)
puts response
const response = await client.search({
  index: "news",
  query: {
    match: {
      content: "elasticsearch",
    },
  },
  aggs: {
    sample: {
      sampler: {
        shard_size: 100,
      },
      aggs: {
        keywords: {
          significant_text: {
            field: "content",
            filter_duplicate_text: true,
          },
        },
      },
    },
  },
});
console.log(response);
GET news/_search
{
  "query": {
    "match": {
      "content": "elasticsearch"
    }
  },
  "aggs": {
    "sample": {
      "sampler": {
        "shard_size": 100
      },
      "aggs": {
        "keywords": {
          "significant_text": {
            "field": "content",
            "filter_duplicate_text": true
          }
        }
      }
    }
  }
}

Результаты анализа нашего очищенного текста, очевидно, имеют более высокое качество для тех, кто знаком с Elastic Stack:

{
  ...
  "aggregations": {
    "sample": {
      "doc_count": 35,
      "keywords": {
        "doc_count": 35,
        "buckets": [
          {
            "key": "elasticsearch",
            "doc_count": 22,
            "score": 11288.001166180758,
            "bg_count": 35
          },
          {
            "key": "logstash",
            "doc_count": 3,
            "score": 1836.648979591837,
            "bg_count": 4
          },
          {
            "key": "kibana",
            "doc_count": 3,
            "score": 1469.3020408163263,
            "bg_count": 5
          }
        ]
      }
    }
  }
}

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

Если ваши дублированные или близкие к дублированию данные можно определить по одному индексированному полю (возможно, хешу текстового содержимого статьи title или полю original_press_release_url), то более эффективно использовать родительскую агрегацию diversified sampler для исключения этих документов из выборки на основе этого единственного ключа. Чем меньше дублирующего содержимого вы можете передать в агрегацию significant_text изначально, тем лучше с точки зрения производительности.

Как вычисляются значения значимости?

Числа, возвращаемые для значений, в основном предназначены для разумной сортировки различных предложений, а не для чего-то, что легко понимается конечными пользователями. Оценки получены из частот документов в фоновых и фоновых наборах. Вкратце, термин считается значимым, если наблюдается заметная разница в частоте появления термина в подмножестве и в фоновом наборе. Способ ранжирования терминов можно настроить, см. раздел «Параметры».

Используйте шаблон «похоже на это, но не это»

Вы можете определить неправильно классифицированное содержимое, сначала выполнив поиск в структурированном поле, например, category:adultMovie, и используйте significant_text для поля «movie_description». Возьмите предложенные слова (я оставлю их на ваш выбор) и выполните поиск по всем фильмам, НЕ помеченным как категория:adultMovie, но содержащих эти ключевые слова. Теперь у вас есть упорядоченный список плохо классифицированных фильмов, которые вы должны переклассифицировать или, по крайней мере, удалить из категории «familyFriendly».

Значение значимости каждого термина также может предоставить полезный параметр boost для сортировки совпадений. Использование параметра minimum_should_match запроса terms с ключевыми словами поможет контролировать баланс точности/полноты в наборе результатов. Высокое значение будет иметь небольшое количество релевантных результатов, заполненных ключевыми словами, а значение «1» приведет к более исчерпывающему набору результатов со всеми документами, содержащими любые ключевые слова.

Ограничения

Отсутствует поддержка дочерних агрегаций

Агрегация `significant_text` намеренно не поддерживает добавление дочерних агрегаций, потому что:

  • Это влечёт большие затраты памяти
  • Это не является полезной функцией, и для тех, кому она нужна, есть обходной путь

Объём кандидатов для терминов обычно очень большой, и они сильно отсеиваются перед возвратом конечных результатов. Поддержка дочерних агрегаций привела бы к дополнительной переработке и была бы неэффективной. Клиенты всегда могут взять сильно сокращённый набор результатов из запроса significant_text и сделать последующий запросом с помощью агрегации terms с клаузой include и дочерними агрегациями для дальнейшего анализа выбранных ключевых слов более эффективным способом.

Отсутствует поддержка вложенных объектов

Агрегация `significant_text` в настоящее время также не может использоваться с текстовыми полями во вложенных объектах, потому что она работает с исходным JSON документа. Это делает эту функцию неэффективной при сопоставлении вложенных документов из хранимого JSON по совпадающему идентификатору документа Lucene.

Приблизительные подсчёты

Количество документов, содержащих термин, предоставленный в результатах, основано на суммировании выборок, возвращаемых каждым фрагментом, и поэтому может быть:

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

Как и большинство проектных решений, это основа компромисса, в котором мы выбрали быструю производительность в ущерб некоторым (как правило, небольшим) неточностям. Однако параметры size и shard size, описанные в следующем разделе, предоставляют инструменты для управления уровнями точности.

Параметры

Эвристики значимости

Эта агрегация поддерживает те же эвристики ранжирования (JLH, mutual_information, gnd, chi_square и т. д.), что и агрегация значимых терминов.

Размер и размер фрагмента

Параметр size может быть установлен для определения того, сколько корзин терминов должно быть возвращено из общего списка терминов. По умолчанию узел, координирующий процесс поиска, запросит каждый фрагмент предоставить свои собственные верхние корзины терминов, и после того, как все фрагменты ответят, он сократит результаты до конечного списка, который затем будет возвращён клиенту. Если количество уникальных терминов больше, чем size, возвращённый список может быть немного неточным (может быть, что счётчики терминов немного неточны, а может быть, что термин, который должен был быть в верхних корзинках размера, не был возвращён).

Для обеспечения большей точности используется кратное значению конечного size в качестве количества терминов, которые необходимо запросить у каждого фрагмента (2 * (size * 1.5 + 10)). Для ручного управления этим параметром можно использовать параметр shard_size для управления объёмами кандидатов терминов, создаваемых каждым фрагментом.

Термины с низкой частотой могут оказаться наиболее интересными после объединения всех результатов, поэтому агрегация `significant_terms` может создавать результаты более высокого качества, когда параметр shard_size установлен на значения, значительно превышающие значение параметра size. Это гарантирует, что больший объём перспективных кандидатов терминов будет получен консолидированной проверкой узлом-редуктором перед окончательным выбором. Очевидно, что большие списки кандидатов терминов приведут к дополнительной сетевой активности и потреблению оперативной памяти, поэтому необходимо найти баланс между качеством и стоимостью. Если shard_size установлен в значение -1 (по умолчанию), то shard_size будет автоматически рассчитано на основе количества фрагментов и параметра size.

shard_size не может быть меньше, чем size (так как это не имеет большого смысла). В противном случае Elasticsearch переопределит его и установит равным size.

Минимальное количество документов

Возможна фильтрация терминов, которые соответствуют большему количеству результатов, чем установленное значение, с помощью опции min_doc_count. Значение по умолчанию равно 3.

Термины с высокими оценками будут собираться на уровне фрагмента и объединяться с терминами, собранными из других фрагментов на втором шаге. Однако фрагмент не имеет информации о глобальных частотах терминов. Решение о добавлении термина в список кандидатов зависит только от оценки, вычисленной на фрагменте с использованием локальных частот фрагментов, а не глобальных частот слова. Критерий min_doc_count применяется только после объединения локальных статистических данных о терминах всех фрагментов. По сути, решение о добавлении термина в качестве кандидата принимается, не имея большой уверенности в том, что термин фактически достигнет необходимого значения min_doc_count. Это может привести к тому, что многие (глобально) часто встречающиеся термины будут отсутствовать в конечном результате, если в списки кандидатов попадут термины с низкой частотой, но высокой оценкой. Чтобы этого избежать, параметр shard_size можно увеличить, чтобы разрешить больше кандидатов терминов на фрагментах. Однако это увеличивает потребление памяти и сетевой трафик.

shard_min_doc_count

Параметр shard_min_doc_count регулирует уверенность фрагмента в том, что термин действительно должен быть добавлен в список кандидатов или нет по отношению к значению min_doc_count. Термины будут рассматриваться только в том случае, если их локальная частота на уровне фрагмента внутри набора превышает shard_min_doc_count. Если ваш словарь содержит много терминов с низкой частотой, и вы не заинтересованы в них (например, в ошибках написания), то вы можете установить параметр shard_min_doc_count для фильтрации кандидатов терминов на уровне фрагмента, которые с достаточной вероятностью не достигнут требуемого значения min_doc_count даже после объединения локальных подсчётов. shard_min_doc_count по умолчанию равен 0 и не имеет эффекта, если вы его явно не зададите.

Установка min_doc_count в значение 1 обычно не рекомендуется, так как она имеет тенденцию возвращать термины, которые являются опечатками или другими странностями. Нахождение более чем одного экземпляра термина помогает усилить то, что, хотя это и редко встречается, термин не является результатом случайного события. Значение по умолчанию 3 используется для обеспечения минимального уровня доказательств. Установка значения shard_min_doc_count слишком высоким приведёт к тому, что значимые термины будут отфильтрованы на уровне фрагмента. Это значение следует установить значительно ниже значения min_doc_count/#shards.

Пользовательский контекст фона

По умолчанию источником статистической информации о фоновых частотах терминов является весь индекс, и этот объём можно сузить с помощью background_filter, чтобы сфокусироваться на значимых терминах в более узком контексте:

resp = client.search(
    index="news",
    query={
        "match": {
            "content": "madrid"
        }
    },
    aggs={
        "tags": {
            "significant_text": {
                "field": "content",
                "background_filter": {
                    "term": {
                        "content": "spain"
                    }
                }
            }
        }
    },
)
print(resp)
response = client.search(
  index: 'news',
  body: {
    query: {
      match: {
        content: 'madrid'
      }
    },
    aggregations: {
      tags: {
        significant_text: {
          field: 'content',
          background_filter: {
            term: {
              content: 'spain'
            }
          }
        }
      }
    }
  }
)
puts response
const response = await client.search({
  index: "news",
  query: {
    match: {
      content: "madrid",
    },
  },
  aggs: {
    tags: {
      significant_text: {
        field: "content",
        background_filter: {
          term: {
            content: "spain",
          },
        },
      },
    },
  },
});
console.log(response);
GET news/_search
{
  "query": {
    "match": {
      "content": "madrid"
    }
  },
  "aggs": {
    "tags": {
      "significant_text": {
        "field": "content",
        "background_filter": {
          "term": { "content": "spain" }
        }
      }
    }
  }
}

Вышеуказанный фильтр поможет сфокусироваться на терминах, специфичных для города Мадрида, а не на таких терминах, как «испанский», которые необычны в контексте всего мира, но распространены в подмножестве документов, содержащих слово «Испания».

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

Обработка сопоставлений источников и индексов

Обычно имя индексированного поля и исходного поля JSON, которое извлекается, совпадают. Однако с более сложными сопоставлениями полей, использующими функции, такие как copy_to, исходное(ые) поле(я) JSON и индексируемое поле, по которому выполняется агрегация, могут отличаться. В таких случаях можно указать поля JSON _source, из которых будет выполняться анализ текста, используя параметр source_fields:

resp = client.search(
    index="news",
    query={
        "match": {
            "custom_all": "elasticsearch"
        }
    },
    aggs={
        "tags": {
            "significant_text": {
                "field": "custom_all",
                "source_fields": [
                    "content",
                    "title"
                ]
            }
        }
    },
)
print(resp)
response = client.search(
  index: 'news',
  body: {
    query: {
      match: {
        custom_all: 'elasticsearch'
      }
    },
    aggregations: {
      tags: {
        significant_text: {
          field: 'custom_all',
          source_fields: [
            'content',
            'title'
          ]
        }
      }
    }
  }
)
puts response
const response = await client.search({
  index: "news",
  query: {
    match: {
      custom_all: "elasticsearch",
    },
  },
  aggs: {
    tags: {
      significant_text: {
        field: "custom_all",
        source_fields: ["content", "title"],
      },
    },
  },
});
console.log(response);
GET news/_search
{
  "query": {
    "match": {
      "custom_all": "elasticsearch"
    }
  },
  "aggs": {
    "tags": {
      "significant_text": {
        "field": "custom_all",
        "source_fields": [ "content", "title" ]
      }
    }
  }
}

Фильтрация значений

Возможна фильтрация значений, по которым будут создаваться корзины (хотя это редко требуется). Это можно сделать с помощью параметров include и exclude, которые основаны на строке регулярного выражения или массиве точных терминов. Эта функциональность повторяет возможности, описанные в документации по агрегации терминов.

© 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-bucket-significanttext-aggregation.html

Spec-Zone.ru

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