查询扩展
查询扩展的动机:提高召回率
问题:考虑查询q: [aircraft],某篇文档d包含“plane”, 但是不包含“aircraft”,显然对于查询q,一个简单的IR系统不会返回文档d,即使d是和q最相关的文档。我们试图改变这种做法:也就是说,我们会返回不包含查询词项的相关文档。
方法:不考虑查询(即与查询无关)及其返回文档情况下对初始查询进行扩展和重构,即进行一次性的全局分析(比如分析整个文档集)来产生同/近义词词典。(对于查询q: [aircraft],查询扩展为[aircraft、plane])。
注:对于查询中的每个查询词项t,可以通过在词典中找出t 的同义词或者相关词对查询进行自动扩展。同义词词典的使用可以与词项的权重计算相结合,比如对增加的查询词项赋予一个低于原始查询词项的权重。
词典生成方法
人工构建的同(近)义词词典(人工编辑人员维护的词典)
自动导出的同(近)义词词典(比如,基于词语的共现统计信息)
基于查询日志挖掘出的查询等价类(Web上很普遍)
同义词词典的自动构建
人工构建同义词词典的代价很大,一种取代思路是通过分析文档集来自动构造这种词典,让机器来构造词典。
通过分析文档集中的词项分布来自动生成同(近)义词词典,基本的想法是计算词语之间的相似度。
基于词的共现信息: 如果两个词各自的上下文共现词类似,那么它们类似
例子:“car” ≈ “motorcycle” ,因为它们都与“road”、“gas” 及“license”之类的词共现,因此它们类似。
基于语法关系: 两个词,如果它们同某些一样的词具有某种给定的语法关系的话,那么它们类似
比如,我们可以认为可生长、可烹调、可取食和可消化的实体很可能是食品, 因此苹果和梨肯定彼此类似
简单地采用词共现信息更具鲁棒性(它不可能会产生语法分析器出错所导致的错误),但是采用语法关系有可能会更精确。
搜索引擎中的查询扩展
搜索引擎进行查询扩展主要依赖的资源:查询日志(query log)
例1: 提交查询[herbs] (草药)后,用户常常搜索[herbal remedies] (草本疗法) → “herbal remedies” 是“herb”的潜在扩展查询
例2: 用户搜索[flower pix] 时常常点击URL photobucket.com/flower,而用户搜索[flower clipart]常常点击同样的URL→ “flower clipart”和“flower pix” 可能互为扩展查询
Lucene中同义词分析器的简单实现
回顾Lucene的分析过程,自定义同义词分析器主要注意两点:
1. 构建自定义的分析器链(analyzer chain)
2. PositionIncrementAttribute设置为0,0增量表示词项与前一词项之间是同义词
代码实现
SynonymAnalyzer
//自定义同义词Analyzer
public class SynonymAnalyzer extends
private
public
this.engine = engine;
}
@Override
//LetterTokenizer->LowerCaseFilter->StopFilter->SynonymFilter分析器链
public
new
new StopFilter(Version.LUCENE_36,
new LowerCaseFilter(Version.LUCENE_36,
new LetterTokenizer(Version.LUCENE_36, reader)),
ENGLISH_STOP_WORDS_SET), engine );
return
}
}
SynonymEngine
//获得同义词列表接口
public interface SynonymEngine {
String[] getSynonyms(String s) throws IOException;
}
SimpleSynonymEngine
//硬编码同义词列表
public class SimpleSynonymEngine implements
private static HashMap<String, String[]> map = new
static
map.put( "quick", new
map.put( "jumps", new
map.put( "over", new
map.put( "lazy", new
map.put( "dog", new
}
public
return map.get(s);
}
}
SynonymFilter
//自定义同义词TokenFilter
public class SynonymFilter extends
public static final String TOKEN_TYPE_SYNONYM
private
private
private AttributeSource.State current;
private final
private final
public
super(in);
new
this.engine = engine;
this.termAtt = addAttribute(CharTermAttribute.class);
this.posIncrAtt = addAttribute(PositionIncrementAttribute.class);
}
public boolean incrementToken() throws
if
char[] syn = synonymStack .pop().toCharArray();
termAtt.copyBuffer(syn, 0, syn.length );
//同义词位置增量设为0
posIncrAtt.setPositionIncrement(0);
return true
}
if
return false
addAliasesToStack();
return true
}
private
return new
}
private boolean addAliasesToStack() throws
String[] synonyms = engine.getSynonyms(getTerm(termAtt ));
if (synonyms == null) {
return false
}
for
synonymStack.push(synonym);
}
return true
}
}
SynonymAnalyzer测试
public static void main(String[] args) throws
new
displayTokensWithFullDetails(new
"The quick brown fox jumps over the lazy dog" );
}
结果输出
2: [quick:4->9:word] [speedy:4->9:word] [fast:4->9:word]
3: [brown:10->15:word]
4: [fox:16->19:word]
5: [jumps:20->25:word] [hops:20->25:word] [leaps:20->25:word]
6: [over:26->30:word] [above:26->30:word]
8: [lazy:35->39:word] [sluggish:35->39:word] [apathetic:35->39:word]
9: [dog:40->43:word] [pooch:40->43:word] [canine:40->43:word]