Отображение Elasticsearch для почтовых индексов Великобритании, способных справляться с интервалами и капатализацией - PullRequest
1 голос
/ 22 марта 2020

Я ищу настройки сопоставления / анализа для Elasticsearch 7 с почтовыми индексами Великобритании. Нам не требуется никакого нечеткого оператора, но мы должны иметь дело с дисперсией в заглавных буквах и интервале.

Некоторые примеры:

Строка запроса:"SN13 9ED" должен вернуть:

  • sn139ed
  • SN13 9ED
  • Sn13 9ed

, но не должен возвращаться:

  • SN13 1EP
  • SN131EP

Анализатор ключевых слов используется по умолчанию, и кажется, что он чувствителен к пробелам, но не к заглавным буквам. Он также будет возвращать совпадение для SN13 1EP, если мы не зададим запрос как SN13 AND 9ED, который нам не нужен.

Кроме того, с помощью анализатора ключевых слов запрос SN13 9ED возвращает результат SN13 1EP с большей релевантностью, чем SN13 9ED, хотя это должно быть точное совпадение. Почему 2 совпадения в одной строке имеют меньшую релевантность, чем просто 1 совпадение?

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

"post_code": {
    "type": "text",
    "fields": {
        "keyword": {
            "type": "keyword",
            "ignore_above": 256
        }
    }
},

Запрос

  "query" => array:1 [▼
    "query_string" => array:1 [▼
      "query" => "KT2 7AJ"
    ]
  ]

Ответы [ 2 ]

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

В дополнение к ответу Opsters, следующее также может быть использовано для решения проблемы с противоположной стороны. Для ответа Opster, они предлагают разделить значение по известному шаблону почтового индекса, и это здорово.

Если мы не знаем шаблон, можно использовать следующее:

{
  "analysis": {
    "filter": {
      "whitespace_remove": {
        "pattern": " ",
        "type": "pattern_replace",
        "replacement": ""
      }
    },
    "analyzer": {
      "no_space_analyzer": {
        "filter": [
          "lowercase",
          "whitespace_remove"
        ],
        "tokenizer": "keyword"
      }
    }
  }
}
{
  "post_code": {
    "type": "text",
    "fields": {
      "keyword": {
        "type": "keyword"
      }
    },
    "analyzer": "no_space_analyzer"
  }
}

Это позволяет нам выполнять поиск с любым интервалом и в любом случае из-за фильтр нижнего регистра.

sn13 1ep, s n 1 3 1 e p, sn131ep все будут совпадать с SN13 1EP

Я думаю, что основным недостатком этой опции является то, что мы больше не получим любые результаты для sn13, поскольку мы не производим токены. Однако sn13* вернет нам результаты.

Можно ли смешать оба эти метода вместе, чтобы мы могли получить лучшее из обоих миров?

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

Я полагаю, что, основываясь на моих комментариях, вы могли отфильтровать SN13 1EP, когда строка поиска будет SN13 9ED.

Надеюсь, вы знаете, что Analysis - это то, как Analyzers работает с полем text и как по умолчанию Standard Analyzer применяется к токенам, прежде чем они в конечном итоге сохраняются в инвертированных индекс. Обратите внимание, что это применимо только к text полям.

Глядя на ваше отображение, если бы вы использовали поиск по post_code, а не post_code.keyword, я считаю, что использование заглавных букв было бы разрешено, поскольку в поле ES для text по умолчанию используется Standard Analyzer, что означает, что вы токены в конечном итоге будут сохранены в индексе в нижнем регистре, и даже при запросе ES во время запроса анализатор будет применен перед поиском в инвертированном индексе.

Обратите внимание, что по умолчанию тот же анализатор, что и настроенный в отображении, применяется в течение индексного времени, а также времени поиска в этом поле

Для сценария ios где у вас есть sn131ep то, что я сделал, использует Filter Token Filter Capture , где я указал регулярное выражение, которое разбило бы токен на две длины 4 и 3 каждый и тем самым сохранить их в инвертированном индексе, который в этом случае будет sn13 и 1ep. Я также собираю их в нижнем регистре, прежде чем сохранить их в перевернутом индексе.

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

Более подробную информацию см. Ниже:

Отображение:

PUT my_postcode_index
{
 "settings" : {
    "analysis" : {
       "filter" : {
          "mypattern" : {
             "type" : "pattern_capture",
             "preserve_original" : true,
             "patterns" : [
                "(\\w{4}+)|(\\w{3}+)",             <--- Note this and feel free to add more patterns
                "\\s"                              <--- Filter based on whitespace
             ]
          }
       },
       "analyzer" : {
          "my_analyzer" : {
             "tokenizer" : "pattern",
             "filter" : [ "mypattern", "lowercase" ]   <--- Note the lowercase here
          }
       }
    }
 },
  "mappings": {
    "properties": {
      "postcode":{        
        "type": "text",
        "analyzer": "my_analyzer",                 <--- Note this 
        "fields":{
          "keyword":{
            "type": "keyword"
          }
        }
      }
    }
  }
}

Образцы документов:

POST my_postcode_index/_doc/1
{
  "postcode": "SN131EP"
}

POST my_postcode_index/_doc/2
{
  "postcode": "sn13 1EP"
}

POST my_postcode_index/_doc/3
{
  "postcode": "sn131ep"
}

Обратите внимание, что эти документы семантически одинаковы.

Запрос запроса:

POST my_postcode_index/_search
{
  "query": {
    "query_string": {
      "default_field": "postcode",
      "query": "SN13 1EP",
      "default_operator": "AND"
    }
  }
}

Ответ:

{
  "took" : 24,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 3,
      "relation" : "eq"
    },
    "max_score" : 0.6246513,
    "hits" : [
      {
        "_index" : "my_postcode_index",
        "_type" : "_doc",
        "_id" : "1",
        "_score" : 0.6246513,
        "_source" : {
          "postcode" : "SN131EP"
        }
      },
      {
        "_index" : "my_postcode_index",
        "_type" : "_doc",
        "_id" : "3",
        "_score" : 0.6246513,
        "_source" : {
          "postcode" : "sn131ep"
        }
      },
      {
        "_index" : "my_postcode_index",
        "_type" : "_doc",
        "_id" : "2",
        "_score" : 0.5200585,
        "_source" : {
          "postcode" : "sn13 1EP"
        }
      }
    ]
  }
}

Обратите внимание, что все три документа возвращаются даже с запросами snp131p и snp13 1ep.

Дополнительное примечание:

Вы можете использовать Analyze API , чтобы выяснить, какие токены созданы для определенного текста

POST my_postcode_index/_analyze
{
  "analyzer": "my_analyzer",
  "text": "sn139ed"
}

И вы ниже можно увидеть, какие токены хранятся в инвертированном индексе.

{
  "tokens" : [
    {
      "token" : "sn139ed",
      "start_offset" : 0,
      "end_offset" : 7,
      "type" : "word",
      "position" : 0
    },
    {
      "token" : "sn13",
      "start_offset" : 0,
      "end_offset" : 7,
      "type" : "word",
      "position" : 0
    },
    {
      "token" : "9ed",
      "start_offset" : 0,
      "end_offset" : 7,
      "type" : "word",
      "position" : 0
    }
  ]
}

Также:

Вы также можете прочитать о Ngram Tokenizer . Я бы посоветовал вам поиграть с обоими решениями и посмотреть, что лучше всего подойдет для вас.

Пожалуйста, проверьте его и дайте мне знать, если у вас есть какие-либо вопросы.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...