Elasticsearch возвращает фонетический токен с поиском
Я использую плагин фонетического анализа из упругого поиска для сопоставления строк благодаря фонетическому преобразованию.
Моя проблема в том, как обработать фонетическое преобразование с помощью упругого поиска в результате запроса?,
Во-первых, я создаю индекс с metaphone
трансформация:
request_body = {
'settings': {
'index': {
'analysis': {
'analyzer': {
'metaphone_analyzer': {
'tokenizer':
'standard',
'filter': [
'ascii_folding_filter', 'lowercase',
'metaphone_filter'
]
}
},
'filter': {
'metaphone_filter': {
'type': 'phonetic',
'encoder': 'metaphone',
'replace': False
},
'ascii_folding_filter': {
'type': 'asciifolding',
'preserve_original': True
}
}
}
}
},
'mappings': {
'person_name': {
'properties': {
'full_name': {
'type': 'text',
'fields': {
'metaphone_field': {
'type': 'string',
'analyzer': 'metaphone_analyzer'
}
}
}
}
}
}
}
res = es.indices.create(index="my_index", body=request_body)
Затем я добавляю некоторые данные:
# Add some data
names = [{
"full_name": "John Doe"
}, {
"full_name": "Bob Alice"
}, {
"full_name": "Foo Bar"
}]
for name in names:
res = es.index(index="my_index",
doc_type='person_name',
body=name,
refresh=True)
И наконец, я запрашиваю имя:
es.search(index="my_index",
body={
"size": 5,
"query": {
"multi_match": {
"query": "Jon Doe",
"fields": "*_field"
}
}
})
Поиск возвращает:
{
'took': 1,
'timed_out': False,
'_shards': {
'total': 5,
'successful': 5,
'skipped': 0,
'failed': 0
},
'hits': {
'total':
1,
'max_score':
0.77749264,
'hits': [{
'_index': 'my_index',
'_type': 'person_name',
'_id': 'AWwYjl4Mqo63y_hLp5Yl',
'_score': 0.77749264,
'_source': {
'full_name': 'John Doe'
}
}]
}
}
В результатах поиска я хотел бы получить фонетическое преобразование имен в упругом поиске (также из имени запроса, но это менее важно), когда я выполняю поиск.
Я знаю, что я мог бы использовать explain
API, но я хотел бы избежать второго запроса, и более того explain
API кажется немного "излишним" для того, чего я хочу достичь.
Спасибо!
1 ответ
Это не похоже на простую реализацию в запросе Elasticsearch, но вы можете попробовать проанализировать API и скриптовые поля с fielddata
включен, и векторы терминов могут пригодиться. Вот как.
Получить токены из произвольного запроса
Analyze API - отличный инструмент, если вы хотите понять, как именно Elasticsearch токенизирует ваш запрос.
Используя ваше отображение, вы можете сделать, например:
GET myindex/_analyze
{
"analyzer": "metaphone_analyzer",
"text": "John Doe"
}
И получить что-то вроде этого в результате:
{
"tokens": [
{
"token": "JN",
"start_offset": 0,
"end_offset": 4,
"type": "<ALPHANUM>",
"position": 0
},
{
"token": "john",
"start_offset": 0,
"end_offset": 4,
"type": "<ALPHANUM>",
"position": 0
},
{
"token": "T",
"start_offset": 5,
"end_offset": 8,
"type": "<ALPHANUM>",
"position": 1
},
{
"token": "doe",
"start_offset": 5,
"end_offset": 8,
"type": "<ALPHANUM>",
"position": 1
}
]
}
Технически это другой запрос, но все же может быть полезным.
Получить токены из поля документа
Теоретически, мы можем попытаться получить те же самые токены, которые анализируют API, возвращенный в предыдущем разделе, из документов, соответствующих нашему запросу.
На практике Elasticsearch не будет хранить токены text
поле, которое он только что проанализировал: fielddata
по умолчанию отключено. Нам нужно включить это:
PUT /myindex
{
"mappings": {
"person_name": {
"properties": {
"full_name": {
"fields": {
"metaphone_field": {
"type": "text",
"analyzer": "metaphone_analyzer",
"fielddata": true
}
},
"type": "text"
}
}
}
},
"settings": {
...
}
}
Теперь мы можем использовать скриптовые поля, чтобы попросить Elasticsearch вернуть эти токены.
Запрос может выглядеть так:
POST myindex/_search
{
"script_fields": {
"my tokens": {
"script": {
"lang": "painless",
"source": "doc[params.field].values",
"params": {
"field": "full_name.metaphone_field"
}
}
}
}
}
И ответ будет выглядеть так:
{
"hits": {
"total": 1,
"max_score": 1,
"hits": [
{
"_index": "myindex",
"_type": "person_name",
"_id": "123",
"_score": 1,
"fields": {
"my tokens": [
"JN",
"T",
"doe",
"john"
]
}
}
]
}
}
Как видите, все те же токены (но в случайном порядке).
Можем ли мы получить информацию о расположении этих токенов в документе?
Получение токенов с их позициями
Термины векторы могут помочь. Чтобы иметь возможность использовать их, нам на самом деле не нужно fielddata
включен. Мы могли бы искать векторы терминов для документа:
GET myindex/person_name/123/_termvectors
{
"fields" : ["full_name.metaphone_field"],
"offsets" : true,
"positions" : true
}
Это вернуло бы что-то вроде этого:
{
"_index": "myindex",
"_type": "person_name",
"_id": "123",
"_version": 1,
"found": true,
"took": 1,
"term_vectors": {
"full_name.metaphone_field": {
"field_statistics": {
"sum_doc_freq": 4,
"doc_count": 1,
"sum_ttf": 4
},
"terms": {
"JN": {
"term_freq": 1,
"tokens": [
{
"position": 0,
"start_offset": 0,
"end_offset": 4
}
]
},
"T": {
"term_freq": 1,
"tokens": [
{
"position": 1,
"start_offset": 5,
"end_offset": 8
}
]
},
"doe": {
"term_freq": 1,
"tokens": [
{
"position": 1,
"start_offset": 5,
"end_offset": 8
}
]
},
"john": {
"term_freq": 1,
"tokens": [
{
"position": 0,
"start_offset": 0,
"end_offset": 4
}
]
}
}
}
}
}
Это дает возможность получить токены поля документа, подобного тому, как их создал анализатор.
К сожалению, насколько мне известно, невозможно объединить эти три запроса в один. Также fielddata
следует использовать с осторожностью, так как он использует много памяти.
Надеюсь это поможет!