Lingpipe中的spell模块-搜索建议

本文介绍Lingpipe实现的搜索建议功能,该功能能够基于用户输入的部分查询词提供拼写纠错和完成查询建议。文章详细阐述了如何利用数量化的短语集、编辑距离和拼写纠错器来实现这一功能。
[b]搜索建议[/b]
Lingpipe提供了一种可选择的拼写纠错方式,能对用户未输入完整的查询进行提示最相近的查询建议。


图片中显示了google搜索框中的选择性纠错模型对查询进行补充完整。
例如,首行搜索建议词是”amzon”,尽管用户输入查询”anaz”,这并不惊奇,因为那些以”anaz”为前缀的建议词的搜索结果比较小。
不仅有词的搜索建议,还有短语纠错建议。比如一些搜索词像”anazao salon”
搜索建议和拼写纠错之间的一个重要不同点为:搜索建议是在确定的搜索短语集中选择的。

I want to find anaz,是没有建议的短语的

找出有数量的短语

例如我们的demo,我们假设用户提供一批包含数量的短语。例如我们提供一批美国各州名及对应人口数。文件格式如下示例:
Alabama 4599000
Alaska 670000
Arizona 6166000
Arkansas 2811000
California 36458000
Colorado 4753000
Connecticut 3505000
Delaware 853000
District of Columbia 58200
Florida 18090000
...


我们刚好使用州人口数(估计数目在2006年中段),用于人口搜索可能不是个好的方式。如果想查询美国各州的人口数却是个好方式。但是如果想找寻找旅游目的地,夏威夷和哥伦比亚特区比其它地方人口建议还多。通常上,数量将要被平衡最流行的结果,然后将反应用户的特殊偏好。

运行命令行demo
我们包含命令行的demo和GUI demo,我们西姆分别描述
1. 命令行
> ant complete-cmd

|N|
-3.95 New York
-5.08 North Carolina
-5.10 New Jersey
-6.90 Nevada
-7.26 New Mexico

|New|
-3.95 New York
-5.10 New Jersey
-7.26 New Mexico
-7.83 New Hampshire
-16.90 Nevada

|New Y|
-3.95 New York
-15.10 New Jersey
-17.26 New Mexico
-17.83 New Hampshire

|New Yor|
-3.95 New York

|Mew |
-13.95 New York
-15.10 New Jersey
-17.26 New Mexico
-17.83 New Hampshire

|U|
-6.87 Utah
-13.04 California
-13.67 Texas
-13.95 New York
-14.05 Florida

|Uta|
-6.87 Utah
-23.04 California

|ZebraFish|


这里用户输入一个查询,下面提示五个自动搜索建议词。其中下面的建议词按照分值排序,分值越高排在越上面。
同样我们也得到那些不是靠前缀匹配的建议词,例如用户输入'<new>时,下面提示的词第五个为''Nevada"。
运行GUI Demo
如果你喜欢玩查询,你既可以通过命令行的方式来得到,也可以通过GUI的方式得到
接口如下图所示:
输入<New Y>下拉框有三个提示
搜索问题
像lingpipe 中的javadoc中解释的那样,这个搜索建议工具能通过前缀匹配得到分值较高最相近的短语。建议短语得分是通过短语得分之和和最高得分来进行计算的,而且是最大似然概率估计打分。另外词的数量被所有数量之和分别进行。例如输入<Mew y>匹配"New York"需要对第一个字母'M'替换为'N'。这中分值利用权重编辑距离来计算,仅仅只为拼写提示。
代码示例
配置搜索建议demo的参数接口,只需要一些正确的短语及其数量组成的构造方法,以及权重编辑距离的搜索参数
下面是命令行的main方法代码,调用类src/AutoCompleteCommand.java
public static void main(String[] args) throws IOException {
File wordsFile = new File(args[0]);
String[] lines = FileLineReader.readLineArray(wordsFile,"ISO-8859-1");
Map<String,Float> counter = new HashMap<String,Float>(200000);
for (String line : lines) {
int i = line.lastIndexOf(' ');
if (i < 0) continue;
String phrase = line.substring(0,i);
String countString = line.substring(i+1);
Float count = Float.valueOf(countString);
counter.put(phrase,count);
}
.


如上代码所示,使用FileLineReader.readLinesArray() 方法,按指定编码将日志词库文件转换为数组。然后将数组中的词语数字插入到Counter(一个map)中。
下一步配置编辑距离参数,来衡量目标短语的前缀与查询前缀的距离值。这个类采用的是 fix-weighted编辑距离,时间上的任何编辑距离都可以使用
double matchWeight = 0.0;
double insertWeight = -10.0;
double substituteWeight = -10.0;
double deleteWeight = -10.0;
double transposeWeight = Double.NEGATIVE_INFINITY;
FixedWeightEditDistance editDistance
= new FixedWeightEditDistance(matchWeight,
deleteWeight,
insertWeight,
substituteWeight,
substituteWeight,
transposeWeight);



最后我们需要配置拼写纠错器:
int maxResults = 5;
int maxQueueSize = 10000;
double minScore = -25.0;
AutoCompleter completer
= new AutoCompleter(counter, editDistance,
maxResults, maxQueueSize, minScore);



此外Counter和编辑距离,最大结果数量,最大搜索队列大小,返回结果最大分值等参数的配置。
最后,我们配置完所有参数并 运行搜索建议demo
for (int i = 1; i < args.length; ++i) {
SortedSet<ScoredObject<String>> completions
= completer.complete(args[i]);



下面java.util.SortedSet包含对象ScoredObject<String>objects,它由字符串和分值组成,
我们得到completions对象后,打印它们:
System.out.println("\n|" + args[i] + "|");
for (ScoredObject<String> so : completions)
System.out.printf("%6.2f %s\n", so.score(), so.getObject());
}


部署搜索建议
总共有3中参数,包括建议调整值,编辑距离和搜索参数。这个编辑距离和拼写纠错中的编辑距离很相似。
最大结果数量需要系统较多资源,所以结果集小相对来说计算简单些。
最大队列数量暗示在搜索建议工具调整前有多大的潜在搜索建议短语集。调整以后,错误结果会尽量减少,大大提高准确率
### 递推关系 对于带权编辑距离问题,考虑序列 $S1[1..i]$ $S2[1..j]$ 的最小权编辑距离 $C[i,j]$,有以下几种情况: 1. **当 $i = 0$ 时**:意味着 $S1$ 为空序列,此时需要将 $S2$ 的 $j$ 个字符全部插入,所以 $C[0,j] = j \times d$。 2. **当 $j = 0$ 时**:意味着 $S2$ 为空序列,此时需要将 $S1$ 的 $i$ 个字符全部删除,所以 $C[i,0] = i \times d$。 3. **当 $i > 0$ 且 $j > 0$ 时**: - 如果 $S1[i] = S2[j]$,则不需要进行任何操作,$C[i,j] = C[i - 1,j - 1]$。 - 如果 $S1[i] \neq S2[j]$,则有三种操作可以选择: - **插入操作**:在 $S1$ 中插入一个字符使其与 $S2[j]$ 匹配,此时 $C[i,j] = C[i,j - 1] + d$。 - **删除操作**:删除 $S1[i]$,此时 $C[i,j] = C[i - 1,j] + d$。 - **替换操作**:将 $S1[i]$ 替换为 $S2[j]$,此时 $C[i,j] = C[i - 1,j - 1] + r$。 综合以上三种操作,取最小值作为 $C[i,j]$ 的值,即 $C[i,j] = \min\{C[i,j - 1] + d, C[i - 1,j] + d, C[i - 1,j - 1] + r\}$。 ### 算法实现 ```python def weighted_edit_distance(S1, S2, d, r): n = len(S1) m = len(S2) # 初始化 C 数组 C = [[0] * (m + 1) for _ in range(n + 1)] # 初始化边界条件 for i in range(n + 1): C[i][0] = i * d for j in range(m + 1): C[0][j] = j * d # 填充 C 数组 for i in range(1, n + 1): for j in range(1, m + 1): if S1[i - 1] == S2[j - 1]: C[i][j] = C[i - 1][j - 1] else: C[i][j] = min(C[i][j - 1] + d, C[i - 1][j] + d, C[i - 1][j - 1] + r) return C[n][m] # 示例用法 S1 = "kitten" S2 = "sitting" d = 1 # 插入删除操作的权 r = 2 # 替换操作的权 result = weighted_edit_distance(S1, S2, d, r) print(result) ``` ### 时间复杂度分析 该算法使用了两层嵌套循环来填充 $C$ 数组,外层循环遍历 $S1$ 的长度 $n$,内层循环遍历 $S2$ 的长度 $m$,因此时间复杂度为 $O(n \times m)$。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值