Объедините все результаты выделения в один консолидированный результат 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

На этот раз мы обрабатываем идентификаторы документов общего термина как выпадающий список. Мы также используем регулярные выражения для замены.

И это наш подход, вы можете найти полный код проекта здесь.

Другие вопросы по тегам