После завершения небольшого проекта мы выбрали подход 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
В настоящее время мы обрабатываем идентификаторы документов общего термина в виде выпадающего списка. Мы также используем регулярные выражения для замены.
И это наш подход, вы можете найти полный код проекта здесь .