查詢擴展
查詢擴展的動機:提高召回率
問題:考慮查詢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 Analyzer {
private SynonymEngine engine ;
public SynonymAnalyzer(SynonymEngine engine) {
this.engine = engine;
}
@Override
//LetterTokenizer->LowerCaseFilter->StopFilter->SynonymFilter分析器鏈
public TokenStream tokenStream(String fieldName, Reader reader) {
TokenStream result = new SynonymFilter(
new StopFilter(Version.LUCENE_36,
new LowerCaseFilter(Version.LUCENE_36,
new LetterTokenizer(Version.LUCENE_36, reader)),
StopAnalyzer. ENGLISH_STOP_WORDS_SET), engine );
return result;
}
}
SynonymEngine
//獲得同義詞列表接口 public interface SynonymEngine { String[] getSynonyms(String s) throws IOException; }
SimpleSynonymEngine
//硬編碼同義詞列表
public class SimpleSynonymEngine implements SynonymEngine {
private static HashMap<String, String[]> map = new HashMap<String, String[]>();
static {
map.put( "quick", new String[] {"fast", "speedy"});
map.put( "jumps", new String[] {"leaps", "hops"});
map.put( "over", new String[] {"above"});
map.put( "lazy", new String[] {"apathetic", "sluggish"});
map.put( "dog", new String[] {"canine", "pooch"});
}
public String[] getSynonyms(String s) {
return map.get(s);
}
}
SynonymFilter
//自定義同義詞TokenFilter
public class SynonymFilter extends TokenFilter {
public static final String TOKEN_TYPE_SYNONYM = "SYNONYM";
private Stack<String> synonymStack ;
private SynonymEngine engine ;
private AttributeSource.State current;
private final CharTermAttribute termAtt;
private final PositionIncrementAttribute posIncrAtt;
public SynonymFilter(TokenStream in, SynonymEngine engine) {
super(in);
synonymStack = new Stack<String>();
this.engine = engine;
this.termAtt = addAttribute(CharTermAttribute.class);
this.posIncrAtt = addAttribute(PositionIncrementAttribute.class);
}
public boolean incrementToken() throws IOException {
if (synonymStack .size() > 0) {
char[] syn = synonymStack .pop().toCharArray();
termAtt.copyBuffer(syn, 0, syn.length );
//同義詞位置增量設為0
posIncrAtt.setPositionIncrement(0);
return true ;
}
if (!input .incrementToken())
return false ;
addAliasesToStack();
return true ;
}
private String getTerm(CharTermAttribute term) {
return new String(term.buffer(), 0, term.length());
}
private boolean addAliasesToStack() throws IOException {
String[] synonyms = engine.getSynonyms(getTerm(termAtt ));
if (synonyms == null) {
return false ;
}
for (String synonym : synonyms) {
synonymStack.push(synonym);
}
return true ;
}
}
SynonymAnalyzer測試
public static void main(String[] args) throws IOException {
SynonymEngine engine = new SimpleSynonymEngine();
AnalyzerUtils. displayTokensWithFullDetails(new SynonymAnalyzer(engine),
"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]