Объедините все результаты выделения в один консолидированный результат ElasticSearch
Мы работаем с перколятором Elasticsearch.
Мы пытаемся показать все выделенные элементы в одном тексте и не получаем много разных результатов. Но, насколько нам известно, это невозможно с текущей версией ElasticSearch. Хотя мы обнаружили, что этого можно достичь с помощью Lucene (обновленная версия), поскольку он поддерживает единый выделенный результат, у нас нет на это времени.
Нам нужны быстрые и простые идеи, чтобы решить эту проблему. Мы обнаружили, что это можно сделать, добавив соответствующие HTML-декорации после, но мы думаем о том, чтобы перечислить каждое слово для каждого результата, а затем использовать этот список, чтобы найти все элементы в исходном тексте, чтобы упорядочить результаты в их появившейся позиции.
Вопрос в том, какой основной и более простой процесс объединяет все результаты ElasticSearch, выделяя результаты в одном консолидированном результате.
Спасибо
1 ответ
Закончив небольшой проект, мы выбрали подход Python.
Основная проблема заключается в том, как ElasticSearch доставляет выделенные результаты: он предназначен для поисковых систем, следовательно, между фрагментами текста с выделенным результатом, а не доставляет полный текст.
По этой причине мы решили выделить результаты с помощью постобработки вместо использования подсветчика ElasticSearch: мы получаем результаты поиска, обрабатываем их с помощью python и, наконец, доставляем полный текст с выделенными словами.
Во-первых, функция для получения результатов запроса:
def get_response(client, index, query):
s = Search().using(client).index(index).query("percolate", field='query', document={'title': query})
response = s.execute()
# get all matches: s.scan() https://elasticsearch-dsl.readthedocs.io/en/latest/search_dsl.html#pagination
return response
Percolator - это класс, которого нет в текущем elasticsearch-dsl-py
Выпуск версии, так что пока мы ее реализуем:
class Percolate(Query):
name = 'percolate'
Во-вторых, мы получаем все условия и их документы id:
def get_highlighted_term(response):
dic_results = defaultdict(list)
for hit in response:
for query in hit.query:
if query == 'span_term':
dic_results[hit.query.span_term.title].append(hit.doc_id)
if query == 'span_near':
phrase = ''
for title in hit.query.span_near.clauses:
phrase += title.span_term.title + ' '
dic_results[phrase[:-1]].append(hit.doc_id)
return dic_results
Мы используем словарь для его универсальности: заголовок / термин в качестве ключа и идентификаторы документа в качестве его значения; это облегчит получение соответствующих значений при выделении текста.
Наконец, мы получаем текст результата:
def get_highlighted_text(dic_results, text):
for term, doc_ids in dic_results.items():
insensitive_term = re.compile(re.escape(term), re.IGNORECASE)
if len(doc_ids) > 1:
result_text = "<ul id='multiple-links'>"
for doc_id in doc_ids:
result_text += "<li><a href='http://localhost/{0}'>{1}</a></li>".format(doc_id, term)
result_text += "</ul>"
text = insensitive_term.sub(result_text, text)
else:
text = insensitive_term.sub('<a href="http://localhost/{}">\g<0></a>'.format(doc_ids[0]), text)
return text
На этот раз мы обрабатываем идентификаторы документов общего термина как выпадающий список. Мы также используем регулярные выражения для замены.
И это наш подход, вы можете найти полный код проекта здесь.