完成这个小项目后,我们选择了 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
这次我们将常用术语的文档 ID 作为下拉列表处理。我们还使用正则表达式进行替换。
这是我们的方法,您可以在此处找到完整的项目代码。