搜索引擎查询扩展

查询扩展

查询扩展的动机:提高召回率

问题:考虑查询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] 

posted on 2012-09-24 15:00 God bless you 阅读(...) 评论(...) 编辑 收藏

导航

统计

公告