Причина, по которой вы видите неожиданные результаты, состоит в том, что и ваш поисковый запрос, и само поле обрабатываются анализатором . Анализаторы разбивают текст на список отдельных терминов, по которым можно выполнять поиск. Вот пример использования конечной точки _analyze :
GET _analyze
{
"analyzer": "standard",
"text": "example.com/critical-illness"
}
{
"tokens" : [
{
"token" : "example.com",
"start_offset" : 0,
"end_offset" : 11,
"type" : "<ALPHANUM>",
"position" : 0
},
{
"token" : "critical",
"start_offset" : 12,
"end_offset" : 20,
"type" : "<ALPHANUM>",
"position" : 1
},
{
"token" : "illness",
"start_offset" : 21,
"end_offset" : 28,
"type" : "<ALPHANUM>",
"position" : 2
}
]
}
Итак, хотя истинное значение ваших документов - example.com/critical-illness
, за кулисами Elasticsearch будет использовать только этот список токенов для совпадений. То же самое происходит с вашим поисковым запросом, поскольку вы используете match_phrase , который токенизирует переданную фразу. Конечным результатом является Elasticsearch пытается сопоставить список токенов ["critical", "illness"]
со списками токенов документов.
В большинстве случаев стандартный анализатор хорошо справляется с удалением ненужных токенов, однако в вашем случае вам важны такие символы, как /
, поскольку вы хотите сопоставить их. Один из способов решить эту проблему - использовать другой анализатор, например анализатор иерархии обратного пути . Ниже приведен пример того, как настроить этот анализатор и использовать его для поля browsing_url
:
PUT /browse_history
{
"settings": {
"analysis": {
"analyzer": {
"url_analyzer": {
"tokenizer": "url_tokenizer"
}
},
"tokenizer": {
"url_tokenizer": {
"type": "path_hierarchy",
"delimiter": "/",
"reverse": true
}
}
}
},
"mappings": {
"properties": {
"browsing_url": {
"type": "text",
"norms": false,
"analyzer": "url_analyzer",
"fields": {
"keyword": {
"type": "keyword",
"ignore_above": 256
}
}
}
}
}
}
Теперь, если вы проанализируете URL-адрес, вы увидите, что пути URL-адресов сохранены целыми:
GET browse_history/_analyze
{
"analyzer": "url_analyzer",
"text": "example.com/critical-illness?src=blah"
}
{
"tokens" : [
{
"token" : "example.com/critical-illness?src=blah",
"start_offset" : 0,
"end_offset" : 37,
"type" : "word",
"position" : 0
},
{
"token" : "critical-illness?src=blah",
"start_offset" : 12,
"end_offset" : 37,
"type" : "word",
"position" : 0
}
]
}
Это позволяет вам выполнить match_phrase_prefix
, чтобы найти все документы с URL-адресами, которые содержат critical-illness
путь:
POST /browse_history/_search
{
"query": {
"match_phrase_prefix": {
"browsing_url": "critical-illness"
}
}
}
{
"took" : 0,
"timed_out" : false,
"_shards" : {
"total" : 1,
"successful" : 1,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : {
"value" : 2,
"relation" : "eq"
},
"max_score" : 1.7896894,
"hits" : [
{
"_index" : "browse_history",
"_type" : "_doc",
"_id" : "3",
"_score" : 1.7896894,
"_source" : {
"browsing_url" : "https://www.example.com/critical-illness"
}
}
]
}
}
EDIT:
Предыдущий ответ перед пересмотром заключался в использовании поля ключевого слова и regexp
, однако это довольно дорогостоящий запрос.
POST /browse_history/_search
{
"query": {
"regexp": {
"browsing_url.keyword": ".*/critical-illness"
}
}
}