issue-2026-03-27-keywords限定-done-0327.txt
3.14 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
@query/query_parser.py @scripts/es_debug_search.py
原始query、以及每一个翻译,都要有一个对应的keywords_query(token分词后,得到名词)
参考这段代码,获取每一个长度大于 1 的名词,然后用空格拼接起来,作为keywords_query
import hanlp
from typing import List, Tuple, Dict, Any
class KeywordExtractor:
"""
基于 HanLP 的名词关键词提取器
"""
def __init__(self):
# 加载带位置信息的分词模型(细粒度)
self.tok = hanlp.load(hanlp.pretrained.tok.CTB9_TOK_ELECTRA_BASE_CRF)
self.tok.config.output_spans = True # 启用位置输出
# 加载词性标注模型
self.pos_tag = hanlp.load(hanlp.pretrained.pos.CTB9_POS_ELECTRA_SMALL)
def extract_keywords(self, query: str) -> str:
"""
从查询中提取关键词(名词,长度 ≥ 2)
Args:
query: 输入文本
Returns:
拼接后的关键词字符串,非连续词之间自动插入空格
"""
query = query.strip()
# 分词结果带位置:[[word, start, end], ...]
tok_result_with_position = self.tok(query)
tok_result = [x[0] for x in tok_result_with_position]
# 词性标注
pos_tag_result = list(zip(tok_result, self.pos_tag(tok_result)))
# 需要忽略的词
ignore_keywords = ['玩具']
keywords = []
last_end_pos = 0
for (word, postag), (_, start_pos, end_pos) in zip(pos_tag_result, tok_result_with_position):
if len(word) >= 2 and postag.startswith('N'):
if word in ignore_keywords:
continue
# 如果当前词与上一个词在原文中不连续,插入空格
if start_pos != last_end_pos and keywords:
keywords.append(" ")
keywords.append(word)
last_end_pos = end_pos
# 可选:打印调试信息
# print(f'分词: {word} | 词性: {postag} | 起始: {start_pos} | 结束: {end_pos}')
return "".join(keywords).strip()
最后,在组织检索表达式时,目前是每一个 query (base_query base_query_trans_en base_query_trans_zh 三种情况)。 会组成一个bool查询,以base_query为例:
"bool": {
"should": [
{
"bool": {
"_name": "base_query",
"must": [
{
"combined_fields": {
...
}
}
],
"should": [
{
"multi_match": {
... "type": "best_fields",
...
},
{
"multi_match": {
...
"type": "phrase",
...
}
}
]
}
},
base_query_trans_en base_query_trans_zh 也是同样
在这个布尔查询的must里面加一项:keywords,搜索的字段和combined_fields一样,命中比例要求50%
结合现有代码做出合理的设计,呈现简单清晰的数据接口,而不是打补丁