Поиск фраз

Из статьи про релевантность мы поняли что искать фразы через query не получится. Но что если очень надо? Тут поможет match_phrase .

Запрос match_phrase используется для поиска близких друг к другу терминов (слов).

GET INDEX/_search
{
  "query": {
    "match_phrase": {
	  "FIELD": "TEXT1 TEXT2"
	}
  }
}

При использовании match_phrase вы повышаете precision но понижаете recall.

Если вы хотите повысить recall запроса match_phrase, вы можете внести некоторую гибкость во фразу, используя параметр slop. Это позволяет терминам (словам) располагаться близко друг к другу, но не обязательно рядом друг с другом, тем самым увеличивая ценность recall. Параметр slop указывает, насколько далеко могут быть друг от друга термины (слова), при этом все еще считая документ совпадающим.

GET INDEX/_search
{
  "query": {
    "match_phrase": {
	  "FIELD": {
	    "query": "TEXT1 TEXT2",
		"slop": 2
	  }	
	} 
  }
}

Т.е следуя из примера между TEXT1 и TEXT2 может быть ещё 2 слова.

Запрос с несколькими совпадениями (multi-match)

Этот тип запроса обеспечивает удобное сокращение для выполнения запроса на совпадение для нескольких полей. Для каждого документа рассчитывается score для каждого поля. Самая высокая из этих score будет score для этого документа.

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

GET INDEX/_search
{
  "query": {
    "multi_match": {
	  "query": "TEXT1 TEXT2",
	  "fields": [
	    "FILED1",
		"FILED2",
		"FILED3"
	  ],
	  "type": "best_fields"
	} 
  }
}

По умолчанию для multi_match используется or для query. Можно также использовать match_phrase указав в поле type значение phrase.

GET INDEX/_search
{
  "query": {
    "multi_match": {
	  "query": "TEXT1 TEXT2",
	  "fields": [
	    "FILED1",
		"FILED2",
		"FILED3"
	  ],
	  "type": "phrase"
	} 
  }
}

Повышение приоритетности поля для вычисления _score

Естественно выполнив запрос выше вы повысили релевантность. Но возможно вы хотите сами задать какое из полей должно иметь приоритетную оценку над другими для _score.

Boost - еще один метод, который можно использовать для улучшения результатов поиска. Допустим, вы хотите, чтобы FILED2 имел больший вес, чем поля FILED1 или FILED3.

GET INDEX/_search
{
  "query": {
    "multi_match": {
	  "query": "TEXT1 TEXT2",
	  "fields": [
	    "FILED1",
		"FILED2^2",
		"FILED3"
	  ],
	  "type": "best_fields"
	} 
  }
}

Борьба с неправильно написанными словами

А что насчёт неправильно написанных слов. Для примера вы ищите слово TEXT1 в поле где его нет, но там есть слово TEXT2. И если вы хотите его всё же найти (TEXT2), то можно воспользоваться fuzziness

GET INDEX/_search
{
  "query": {
    "match": {
	  "FILED": {
	    "query": "TEXT1",
		"fuzziness": 1
	  }
	}  
  }
}

Если вы не знаете какое значение подставить для fuzziness можно использовать auto.

При использовании fuzziness стоит помнить что это создаст дополнительную нагрузку на CPU.