Elasticsearch Edge NGram токенайзер выше, когда слово начинается с n-граммы - PullRequest
0 голосов
/ 10 ноября 2018

Предположим, есть следующее сопоставление с Edge NGram Tokenizer:

{
  "settings": {
    "analysis": {
      "analyzer": {
        "autocomplete_analyzer": {
          "tokenizer": "autocomplete_tokenizer",
          "filter": [
            "standard"
          ]
        },
        "autocomplete_search": {
          "tokenizer": "whitespace"
        }
      },
      "tokenizer": {
        "autocomplete_tokenizer": {
          "type": "edge_ngram",
          "min_gram": 1,
          "max_gram": 10,
          "token_chars": [
            "letter",
            "symbol"
          ]
        }
      }
    }
  },
  "mappings": {
    "tag": {
      "properties": {
        "id": {
          "type": "long"
        },
        "name": {
          "type": "text",
          "analyzer": "autocomplete_analyzer",
          "search_analyzer": "autocomplete_search"
        }
      }
    }
  }
}

И индексируются следующие документы:

POST /tag/tag/_bulk
{"index":{}}
{"name" : "HITS FIND SOME"}
{"index":{}}
{"name" : "TRENDING HI"}
{"index":{}}
{"name" : "HITS OTHER"}

Затем поиск

{
  "query": {
    "match": {
      "name": {
        "query": "HI"
      }
    }
  }
}

дает всех с одинаковым счетом или TRENDING - HI с результатом выше, чем у других.

Как это можно настроить, чтобы показывать с более высоким счетом записи, которые фактически начинаются с n-граммы искателя? В этом случае HITS FIND SOME и HITS OTHER должны иметь более высокий балл, чем TRENDING HI; в то же время TRENDING HI должен быть в результатах.

Также используется маркер, поэтому данное решение не должно его испортить.

В запросе используется маркер:

 "highlight": {
    "pre_tags": [
      "<"
    ],
    "post_tags": [
      ">"
    ],
    "fields": {
      "name": {}
    }
  }

Использование этого с match_phrase_prefix портит подсветку, давая <H><I><T><S> FIND SOME при поиске только H.

Ответы [ 3 ]

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

Вы должны понимать, какasticsearch / lucene анализирует ваши данные и вычисляет результат поиска.

1. Анализ API

https://www.elastic.co/guide/en/elasticsearch/reference/current/_testing_analyzers.html это покажет вам, что будет хранить эластичный поиск, в вашем случае:

T / TR / TRE /.... TRENDING / / H / HI

2. Score

https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-bool-query.html

Запрос bool часто используется для создания сложного запроса, когда вам нужен конкретный вариант использования. Используйте must для фильтрации документов, затем should для оценки. Обычный вариант использования - использование разных анализаторов в одном поле (используя ключевое слово fields в отображении, вы можете анализировать одно и то же поле по-разному).

3. не путайте выделения

Согласно документу: https://www.elastic.co/guide/en/elasticsearch/reference/current/search-request-highlighting.html#specify-highlight-query

Вы можете добавить дополнительный запрос:

{
  "query": {
    "bool": {
            "must" : [
                        {
          "match": {
            "name": "HI"
          }
        }
            ],
      "should": [
        {
          "prefix": {
            "name": "HI"
          }
        }
      ]
    }
  },
     "highlight": {
    "pre_tags": [
      "<"
    ],
    "post_tags": [
      ">"
    ],
    "fields": {
      "name": {
                "highlight_query": {
                        "match": {
            "name": "HI"
          }
                }
            }
    }
  }
}
0 голосов
/ 19 ноября 2018

Возможное решение этой проблемы - использовать мультиполя . Они позволяют по-разному индексировать одни и те же данные из исходного документа. В вашем случае вы можете индексировать поле name по умолчанию text, затем как ngrams, а также как edgengrams . Тогда запрос должен быть bool запрос по сравнению со всеми этими fields.

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

В вашем случае все документы будут соответствовать ngram HI. Но только HITS FIND SOME и HITS OTHER документ получат дополнительный балл edgengram. Это дало бы толчок этим двум документам и поставило бы их на первое место. Сложность заключается в том, что вы должны убедиться, что edgengram не разделяется на пробелы, потому что тогда HI в конце получит ту же оценку, что и в начале документа.

Вот пример сопоставления и запроса для вашего случая:

PUT /tag/
{
    "settings": {
        "analysis": {
            "analyzer": {
                "edge_analyzer": {
                    "tokenizer": "edge_tokenizer"
                },
                "kw_analyzer": {
                    "tokenizer": "kw_tokenizer"
                },
                "ngram_analyzer": {
                    "tokenizer": "ngram_tokenizer"
                },
                "autocomplete_analyzer": {
                    "tokenizer": "autocomplete_tokenizer",
                    "filter": [
                        "standard"
                    ]
                },
                "autocomplete_search": {
                    "tokenizer": "whitespace"
                }
            },
            "tokenizer": {
                "kw_tokenizer": {
                    "type": "keyword"
                },
                "edge_tokenizer": {
                    "type": "edge_ngram",
                    "min_gram": 2,
                    "max_gram": 10
                },
                "ngram_tokenizer": {
                    "type": "ngram",
                    "min_gram": 2,
                    "max_gram": 10,
                    "token_chars": [
                        "letter",
                        "digit"
                    ]
                },
                "autocomplete_tokenizer": {
                    "type": "edge_ngram",
                    "min_gram": 1,
                    "max_gram": 10,
                    "token_chars": [
                        "letter",
                        "symbol"
                    ]
                }
            }
        }
    },
    "mappings": {
        "tag": {
            "properties": {
                "id": {
                    "type": "long"
                },
                "name": {
                    "type": "text",
                    "fields": {
                        "edge": {
                            "type": "text",
                            "analyzer": "edge_analyzer"
                        },
                        "ngram": {
                            "type": "text",
                            "analyzer": "ngram_analyzer"
                        }
                    }
                }
            }
        }
    }
}

И запрос:

POST /tag/_search
{
    "query": {
        "bool": {
            "should": [
                {
                "function_score": {
                    "query": {
                        "match": {
                            "name.edge": {
                                "query": "HI"
                            }
                        }
                    },
                    "boost": "5",
                    "boost_mode": "multiply"
                }
                },
                {
                    "match": {
                        "name.ngram": {
                            "query": "HI"
                        }
                    }
                },
                {
                    "match": {
                        "name": {
                            "query": "HI"
                        }
                    }
                }
            ]
        }
    }
}
0 голосов
/ 10 ноября 2018

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

{
  "query": {
    "bool": {
      "should": [
        {
          "match": {
            "name": "HI"
          }
        },
        {
          "match_phrase_prefix": {
            "name": "HI"
          }
        }
      ]
    }
  }
}

Термин match будет совпадать для всех трех результатов, но match_phrase_prefix не будет совпадать для TRENDING HI. В результате вы получите все три элемента в результатах, но TRENDING HI появится с меньшим количеством баллов.

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

Запрос match_phrase_prefix является автозаполнением бедняги [...]. Для лучших решений для поиска по мере ввода см. Подсказку для завершения и поиск по индексу по времени как тип.

В дополнение к этому, если вы вводите этот запрос bool, вы, вероятно, захотите взглянуть на параметр minimum_should_match, в зависимости от желаемых результатов.

...