下面是一个 Python 示例:根据"无法识别"的搜索词,从已知词库/历史搜索词中找出可能想输入的内容,并记录未知搜索词和候选结果。
```python
import difflib
import json
from collections import Counter, defaultdict
class SearchSuggester:
def init(self, known_words, history_queries=None, min_score=0.3):
已知可识别词库
self.known_words = set(known_words)
历史搜索词,可作为候选池
self.history_queries = list(history_queries or \[\])
self.min_score = min_score
记录无法识别的搜索词出现次数
self.unknown_counter = Counter()
记录每个未知搜索词对应的候选输入
self.candidate_log = defaultdict(list)
def is_recognized(self, query: str) -> bool:
"""判断搜索词是否可识别,这里简单判断是否在已知词库中"""
return query in self.known_words
@staticmethod
def _edit_distance(a: str, b: str) -> int:
"""计算编辑距离,用于衡量字符串相似程度"""
m, n = len(a), len(b)
dp = list(range(n + 1))
for i in range(1, m + 1):
prev = dp0
dp0 = i
for j in range(1, n + 1):
tmp = dpj
if ai - 1 == bj - 1:
dpj = prev
else:
dpj = min(prev, dpj, dpj - 1) + 1
prev = tmp
return dpn
def _score(self, query: str, candidate: str) -> float:
"""综合相似度评分"""
序列相似度
seq_score = difflib.SequenceMatcher(None, query, candidate).ratio()
编辑距离相似度
dist = self._edit_distance(query, candidate)
edit_score = 1 - dist / max(len(query), len(candidate), 1)
前缀、包含关系加分
prefix_bonus = 0.08 if candidate.startswith(query) else 0.0
contains_bonus = 0.04 if query in candidate else 0.0
return 0.55 * seq_score + 0.45 * edit_score + prefix_bonus + contains_bonus
def suggest(self, query: str, top_n: int = 5):
"""为未知搜索词推荐可能输入"""
pool = set(self.history_queries) | self.known_words
scored = \[\]
for word in pool:
if word == query:
continue
score = self._score(query, word)
if score >= self.min_score:
scored.append((word, round(score, 4)))
scored.sort(key=lambda x: x1, reverse=True)
return scored:top_n
def collect(self, query: str, top_n: int = 5):
"""
搜集无法识别的搜索词及其可能输入内容。
如果搜索词可识别,则不记录,直接返回空列表。
"""
if self.is_recognized(query):
return \[\]
self.unknown_counterquery += 1
suggestions = self.suggest(query, top_n=top_n)
self.candidate_logquery = suggestions
return suggestions
def dump(self, path: str):
"""将搜集结果保存到 JSON 文件"""
data = {
"unknown_counter": dict(self.unknown_counter),
"candidate_log": dict(self.candidate_log),
}
with open(path, "w", encoding="utf-8") as f:
json.dump(data, f, ensure_ascii=False, indent=2)
if name == "main":
known_words = {
"苹果手机", "华为手机", "小米手机", "蓝牙耳机", "机械键盘"
}
history_queries = [
"苹果手机", "苹果电脑", "华为手机", "小米手机",
"蓝牙耳机", "机械键盘", "显示器", "笔记本电脑"
]
suggester = SearchSuggester(known_words, history_queries)
test_queries = [
"苹果手几",
"篮牙耳机",
"机械健盘",
"苹果手机", # 可识别,不会被记录
]
for q in test_queries:
result = suggester.collect(q)
print(f"搜索词: {q!r} -> 可能输入: {result}")
print("\n未知词统计:", suggester.unknown_counter)
print("候选记录:", dict(suggester.candidate_log))
保存搜集结果
suggester.dump("unknown_query_candidates.json")
```
输出示例:
```text
搜索词: '苹果手几' -> 可能输入: ('苹果手机', 0.9), ('苹果电脑', 0.5), ...
搜索词: '篮牙耳机' -> 可能输入: ('蓝牙耳机', 0.9), ...
搜索词: '机械健盘' -> 可能输入: ('机械键盘', 0.9), ...
搜索词: '苹果手机' -> 可能输入: \[\]
```
这个实现的核心是:
-
判断搜索词是否在已知词库中;
-
如果无法识别,就从历史搜索词和已知词库中找相似词;
-
使用编辑距离和字符串相似度综合打分;
-
记录未知搜索词及其候选内容,方便后续分析或人工审核。
实际生产中可以进一步使用 rapidfuzz、拼音纠错、Elasticsearch Suggest、用户点击日志等提升效果。
文章仅供参考用。