Не быть лучшим, но мои два цента!!
Я не думаю, что Elasticsearch предоставляет точное готовое решение для этого варианта использования. Самый близкий способ сделать то, что вы хотите, — это использовать Больше лайков.
Этот запрос помогает найти документы, похожие на сам документ, который вы предоставляете в качестве входных данных.
В основном алгоритм такой:
- Найдите лучшие K терминов с самым высоким tf-idf из входного документа.
- Вы можете указать из ввода, что min_term_частота слов должна быть 1 или 2, и, глядя на ваш вариант использования, это будет
1
. Смысл рассматривать только те слова из входного документа, частота терминов которых равна 1
.
- Построить N дизъюнктивных запросов на основе этих терминов, а точнее логического оператора ИЛИ
- Эти N номеров настраиваются в запросе запроса, по умолчанию это
25
, а свойство max_query_terms
.
- Выполняйте запросы внутренне и возвращайте наиболее похожие документы.
Более точно по этой ссылке< / а>,
Запрос MLT просто извлекает текст из входного документа, анализирует его, обычно используя тот же анализатор, что и поле, а затем выбирает K лучших терминов с наивысшим значением tf-idf для формирования дизъюнктивного запроса этих терминов.
Давайте посмотрим, как мы можем достичь некоторых вариантов использования, которые вы упомянули.
Вариант использования 1: Найдите документы страницы, имеющей min_word_match_score 2.
Обратите внимание, что ваше поле pages
должно иметь значение nested
типа. В противном случае использование типа object
было бы невозможно. для этого сценария. Я предлагаю вам пройти по вышеупомянутым ссылкам, чтобы узнать больше об этом.
Скажем, у меня есть два индекса
- my_book_index — документы для поиска
- my_book_index_input — документы будут использоваться в качестве входных документов.
Оба будут иметь структуру отображения, как показано ниже:
{
"mappings": {
"properties": {
"book_id":{
"type": "keyword"
},
"pages":{
"type": "nested"
}
}
}
}
Примеры документов для my_book_index:
POST my_book_index/_doc/1
{
"book_id":"book01",
"pages":[
{ "page_id":1, "words":["11", "12", "13", "14", "105"] },
{ "page_id":2, "words":["21", "22", "23", "24", "205"] },
{ "page_id":3, "words":["31", "32", "33", "34", "305"] },
{ "page_id":4, "words":["41", "42", "43", "44", "405"] }
]
}
POST my_book_index/_doc/2
{
"book_id":"book02",
"pages":[
{ "page_id":1, "words":["11", "12", "13", "104", "105"] },
{ "page_id":2, "words":["21", "22", "23", "204", "205"] },
{ "page_id":3, "words":["301", "302", "303", "304", "305"] },
{ "page_id":4, "words":["401", "402", "403", "404", "405"] }
]
}
POST my_book_index/_doc/3
{
"book_id":"book03",
"pages":[
{ "page_id":1, "words":["11", "12", "13", "100", "105"] },
{ "page_id":2, "words":["21", "22", "23", "200", "205"] },
{ "page_id":3, "words":["301", "302", "303", "300", "305"] },
{ "page_id":4, "words":["401", "402", "403", "400", "405"] }
]
}
Образец документа для my_book_index_input:
POST my_book_index_input/_doc/1
{
"book_id":"book_new",
"pages":[
{ "page_id":1, "words":["11", "12", "13", "14", "15"] },
{ "page_id":2, "words":["21", "22", "23", "24", "25"] }
]
}
Больше нравится этот запрос:
Случай использования: В основном я заинтересован в поиске документов, которые были бы похожи на вышеупомянутые документы, имеющие 4 matches in page 1
или 4 matches in page 2
POST my_book_index/_search
{
"size": 10,
"_source": "book_id",
"query": {
"nested": {
"path": "pages",
"query": {
"more_like_this" : {
"fields" : ["pages.words"],
"like" : [
{
"_index": "my_book_index_input",
"_id": 1
}
],
"min_term_freq" : 1,
"min_doc_freq": 1,
"max_query_terms" : 25,
"minimum_should_match": 4
}
},
"inner_hits": {
"_source": ["pages.page_id", "pages.words"]
}
}
}
}
В основном я хочу искать в my_book_index
все документы, похожие на _doc:1
в индексе my_book_index_input
.
Обратите внимание на каждый параметр в запросе. Я предлагаю вам пройти построчно, чтобы понять все это.
Обратите внимание на ответ ниже при выполнении этого запроса:
Ответ:
{
"took" : 71,
"timed_out" : false,
"_shards" : {
"total" : 1,
"successful" : 1,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : {
"value" : 1,
"relation" : "eq"
},
"max_score" : 6.096043,
"hits" : [
{
"_index" : "my_book_index",
"_type" : "_doc",
"_id" : "1",
"_score" : 6.096043,
"_source" : {
"book_id" : "book01" <---- Document 1 returns
},
"inner_hits" : {
"pages" : {
"hits" : {
"total" : {
"value" : 2, <---- Number of pages hit for this document
"relation" : "eq"
},
"max_score" : 6.096043,
"hits" : [
{
"_index" : "my_book_index",
"_type" : "_doc",
"_id" : "1",
"_nested" : {
"field" : "pages",
"offset" : 0
},
"_score" : 6.096043,
"_source" : {
"page_id" : 1, <---- Page 1 returns as it has 4 matches
"words" : [
"11",
"12",
"13",
"14",
"105"
]
}
},
{
"_index" : "my_book_index",
"_type" : "_doc",
"_id" : "1",
"_nested" : {
"field" : "pages",
"offset" : 1
},
"_score" : 6.096043,
"_source" : {
"page_id" : 2, <--- Page 2 returns as it also has 4 matches
"words" : [
"21",
"22",
"23",
"24",
"205"
]
}
}
]
}
}
}
}
]
}
}
Обратите внимание, что возвращается только документ с book_id: 1. Причина проста. Я упомянул следующие свойства в запросе:
"min_term_freq" : 1,
"min_doc_freq": 1,
"max_query_terms" : 25,
"minimum_should_match": 4
По сути, рассматривайте только те термины для поиска во входном документе, чья частота термина равна 1, который доступен в минимум 1 документе, а количество совпадений в одном вложенном документе должно быть 4.
Измените параметры, например. min_doc_freq
до 3
и min_should_match
до 3
, вы должны увидеть еще несколько документов.
Обратите внимание, что вы не увидите весь документ, отвечающий указанным выше свойствам, из-за того, как он был реализован. Помните шаги, которые я упомянул в начале. Возможно, поэтому.
Вариант использования 2: вариант использования 1 + вернуть только те, у которых min page match
равно 2
Я не уверен, поддерживается ли это, т.е. adding filter to inner_hits based on _count of inner_hits
, однако я считаю, что это то, что вы можете добавить на уровне своего приложения. По сути, получите приведенный выше ответ, рассчитайте inner_hits.pages.hits.total_value
и, таким образом, верните потребителю только те документы. В основном ниже показано, как будет выглядеть ваш поток ответов на запросы:
For Request: Client Layer (UI) ---> Service Layer --> Elasticsearch
For Response: Elasticsearch ---> Service Layer (filter logic for n pages match) --> Client Layer (or UI)
Это может быть не лучшее решение и иногда может давать вам результаты, которые могут не соответствовать вашим ожиданиям, но я бы посоветовал хотя бы попробовать, поскольку единственное другое решение вместо использования этого запроса, к сожалению, написать ваш собственный клиентский код, который будет использовать TermVectorAPI как указано в эта ссылка.
Вспомните алгоритм, как работает запрос MLT, и посмотрите, сможете ли вы копнуть глубже, почему результаты возвращаются такими, какие они есть.
Не уверен, что это так, но я надеюсь, что это поможет!
person
Opster ES Ninja - Kamal
schedule
19.03.2020
pages
имеет типnested
илиobject
? - person Opster ES Ninja - Kamal   schedule 18.03.2020