美文网首页Java技术文章@IT·互联网程序员
Lucene--相关度排序和中文分析器

Lucene--相关度排序和中文分析器

作者: 我可能是个假开发 | 来源:发表于2017-05-19 15:12 被阅读471次

    一、相关度排序

    1.什么是相关度排序

    相关度排序是查询结果按照与查询关键字的相关性进行排序,越相关的越靠前。比如搜索“Lucene”关键字,与该关键字最相关的文章应该排在前边。

    2.相关度打分

    Lucene对查询关键字和索引文档的相关度进行打分,得分高的就排在前边。如何打分呢?Lucene是在用户进行检索时实时根据搜索的关键字计算出来的,分两步:

    1. 计算出词(Term)的权重
    2. 根据词的权重值,计算文档相关度得分。

    什么是词的权重?
    明确索引的最小单位是一个Term(索引词典中的一个词),搜索也是要从Term中搜索,再根据Term找到文档,Term对文档的重要性称为权重,影响Term权重有两个因素:

    • Term Frequency (tf):
      指此Term在此文档中出现了多少次。tf 越大说明越重要。 词(Term)在文档中出现的次数越多,说明此词(Term)对该文档越重要,如“Lucene”这个词,在文档中出现的次数很多,说明该文档主要就是讲Lucene技术的。

    • Document Frequency (df):
      指有多少文档包含次Term。df 越大说明越不重要。
      比如,在一篇英语文档中,this出现的次数更多,就说明越重要吗?不是的,有越多的文档包含此词(Term), 说明此词(Term)太普通,不足以区分这些文档,因而重要性越低。

    3.设置boost值影响相关度排序

    boost是一个加权值(默认加权值为1.0f),它可以影响权重的计算。

    • 在索引时对某个文档中的field设置加权值高,在搜索时匹配到这个文档就可能排在前边。
    • 在搜索时对某个域进行加权,在进行组合域查询时,匹配到加权值高的域最后计算的相关度得分就高。

    设置boost是给域(field)或者Document设置的。

    3.1 在创建索引时设置

    如果希望某些文档更重要,当此文档中包含所要查询的词则应该得分较高,这样相关度排序可以排在前边,可以在创建索引时设定文档中某些域(Field)的boost值来实现,如果不进行设定,则Field Boost默认为1.0f。一旦设定,除非删除此文档,否则无法改变。

    @Test
    public void setBoost4createIndex() throws Exception {
        // 创建分词器
        Analyzer analyzer = new StandardAnalyzer();
    
        IndexWriterConfig cfg = new IndexWriterConfig(Version.LUCENE_4_10_3,
                analyzer);
        Directory directory = FSDirectory.open(new File("E:\\11-index\\0728"));
        // 创建IndexWriter对象,通过它把分好的词写到索引库中
        IndexWriter writer = new IndexWriter(directory, cfg);
    
        Document doc = new Document();
        Field id = new StringField("id", "11", Store.YES);
        Field description = new TextField("description", "测试设置BOOST值 lucene",
                Store.YES);
        // 设置boost
        description.setBoost(10.0f);
        // 把域添加到文档中
        doc.add(id);
        doc.add(description);
        writer.addDocument(doc);
        // 关闭IndexWriter
        writer.close();
    }
    

    输出:

    输出.png

    3.2 在查询索引时设置

    在MultiFieldQueryParser创建时设置boost值。

    @Test
    public void multiFieldQueryParser() throws Exception {
        // 创建7.3.2 MultiFieldQueryParser
        // 默认搜索的多个域的域名
        String[] fields = { "name", "description" };
        Analyzer analyzer = new StandardAnalyzer();
        Map<String, Float> boosts = new HashMap<String, Float>();
        boosts.put("name", 200f);
        MultiFieldQueryParser parser = new MultiFieldQueryParser(fields,
                analyzer, boosts);
    
        // Query query = parser.parse("name:lucene OR description:lucene");
        //等同于name:lucene OR description:lucene
        Query query = parser.parse("java");
        System.out.println(query);
        doSearch(query);
    }
    

    二、中文分词器

    1.什么是中文分词器

    英文是以单词为单位的,单词与单词之间以空格或者逗号句号隔开。而中文则以字为单位,字又组成词,字和词再组成句子。所以对于英文,我们可以简单以空格判断某个字符串是否为一个单词,比如I love China,love 和 China很容易被程序区分开来;但中文“我爱中国”就不一样了,电脑不知道“中国”是一个词语还是“爱中”是一个词语。把中文的句子切分成有意义的词,就是中文分词,也称切词。我爱中国,分词的结果是:我 爱 中国。

    2.Lucene自带的中文分词器

    • StandardAnalyzer:
      单字分词:就是按照中文一个字一个字地进行分词。如:“我爱中国”,
      效果:“我”、“爱”、“中”、“国”。

    • CJKAnalyzer:
      二分法分词:按两个字进行切分。如:“我是中国人”,效果:“我是”、“是中”、“中国”“国人”。

    上边两个分词器无法满足需求。

    3.第三方中文分词器

    • paoding: 庖丁解牛最新版在 https://code.google.com/p/paoding/ 中最多支持Lucene 3.0,且最新提交的代码在 2008-06-03,在svn中最新也是2010年提交,已经过时,不予考虑。

    • mmseg4j:最新版已从 https://code.google.com/p/mmseg4j/ 移至 https://github.com/chenlb/mmseg4j-solr,支持Lucene 4.10,且在github中最新提交代码是2014年6月,从09年~14年一共有:18个版本,也就是一年几乎有3个大小版本,有较大的活跃度,用了mmseg算法。

    • IK-analyzer: 最新版在https://code.google.com/p/ik-analyzer/上,支持Lucene 4.10从2006年12月推出1.0版开始, IKAnalyzer已经推出了4个大版本。最初,它是以开源项目Luence为应用主体的,结合词典分词和文法分析算法的中文分词组件。从3.0版本开 始,IK发展为面向Java的公用分词组件,独立于Lucene项目,同时提供了对Lucene的默认优化实现。在2012版本中,IK实现了简单的分词 歧义排除算法,标志着IK分词器从单纯的词典分词向模拟语义分词衍化。 但是也就是2012年12月后没有在更新。

    • ansj_seg:最新版本在 https://github.com/NLPchina/ansj_seg tags仅有1.1版本,从2012年到2014年更新了大小6次,但是作者本人在2014年10月10日说明:“可能我以后没有精力来维护ansj_seg了”,现在由”nlp_china”管理。2014年11月有更新。并未说明是否支持Lucene,是一个由CRF(条件随机场)算法所做的分词算法。

    • imdict-chinese-analyzer:最新版在 https://code.google.com/p/imdict-chinese-analyzer/ , 最新更新也在2009年5月,下载源码,不支持Lucene 4.10 。是利用HMM(隐马尔科夫链)算法。

    • Jcseg:最新版本在git.oschina.net/lionsoul/jcseg,支持Lucene 4.10,作者有较高的活跃度。利用mmseg算法。

    4.使用中文分词器IKAnalyzer

    Ikanalyzer.png

    IKAnalyzer继承Lucene的Analyzer抽象类,使用IKAnalyzer和Lucene自带的分析器方法一样,将Analyzer测试代码改为IKAnalyzer测试中文分词效果。

    如果使用中文分词器ik-analyzer,就在索引和搜索程序中使用一致的分词器ik-analyzer。

    4.1添加jar包

    jar包.png

    4.2 修改分词器代码

    // 创建分词器,标准分词器
    // Analyzer analyzer = new StandardAnalyzer();
    // 使用ikanalyzer
    Analyzer analyzer = new IKAnalyzer();
    

    5.扩展中文词库

    将以下文件拷贝到config目录下

    所需的文件.png

    从ikanalyzer包中拷贝配置文件到classpath下。

    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">  
    <properties>  
    
        <comment>IK Analyzer 扩展配置</comment>
        <!-- 用户可以在这里配置自己的扩展字典 -->
         <entry key="ext_dict">dicdata/mydict.dic</entry> 
         <!-- 用户可以在这里配置自己的扩展停用词字典    -->
        <entry key="ext_stopwords">dicdata/ext_stopword.dic</entry> 
    
    </properties>
    

    如果想配置扩展词和停用词,就创建扩展词的文件和停用词的文件,文件的编码要是utf-8。

    注意:不要用记事本保存扩展词文件和停用词文件,那样的话,格式中是含有bom的。

    添加扩展词文件:ext.dic,内容:我爱中国

    6.使用luke测试中文分词

    第一步:将ikanalyzer的jar包,拷贝到luke工具的目录

    测试1.png

    使用Luke测试第三方分词器分词效果,需通过java.ext.dirs加载jar包:
    可简单的将第三方分词器和lukeall放在一块儿,cmd下运行:

    11.png

    第二步:使用命令打开luke工具:

    java -Djava.ext.dirs=. -jar lukeall-4.10.3.jar
    
    测试2.png

    相关文章

      网友评论

        本文标题: Lucene--相关度排序和中文分析器

        本文链接:https://www.haomeiwen.com/subject/npuyxxtx.html