IKAnalyzer结合Lucene使用和单独使用例子 简单性能测试
本文由发表于3年前 | J2EE | 评论数 3 |  被围观 11,192 views+
使用到的Jar包:结合Lucene使用直接通过Analyzer进行分词使用IKSegmenter进行分词性能测试:

IKAnalyzer是一个开源基于JAVA语言的轻量级的中文分词第三方工具包,采用了特有的“正向迭代最细粒度切分算法“,支持细粒度和智能分词两种切分模式。刚开始使用的时候,发现不能支持中文和字母混合的分词,例如:iPhone5s土豪金。后来发现在2012版本,词典支持中文,英文,数字混合词语,并且优化了词典存储,内存更小的占用。支持用户词典扩展定义。为了更好的测试,这里就使用了IKAnalyzer2012_u6这个版本。

使用到的Jar包:
  • IKAnalyzer2012_u6.jar
  • lucene-core-3.6.0.jar

把 IKAnalyzer中的IKAnalyzer.cfg.xml, ext.dic(如果找不到,可以手动创建一个该文件), stopword.dic文件放到代码的根目录中。

结合Lucene使用

下载下来的Jar包是包含了结合Lucene使用的例子,先把要检索的内容,写入Lucene索引,然后根据需要查找的关键词,通过Lucene的QueryParser对象进行解析查找,构造该QueryParser对象的时候,传入了IKAnalyzer,进而通过IKAnalyzer进行分词:

Analyzer analyzer = new IKAnalyzer(true);
QueryParser qp = new QueryParser(Version.LUCENE_34, fieldName, analyzer);

ext.dic词典如下:

iPhone5s土豪金
2014巴西世界杯

完整代码如下:

// 使用Lucene分词  
//Lucene Document的域名
String fieldName = "text";
//检索内容
String text = "据说WWDC要推出iPhone6要出了?与iPhone5s土豪金相比怎样呢?";
//实例化IKAnalyzer分词器
Analyzer analyzer = new IKAnalyzer(true);

Directory directory = null;
IndexWriter iwriter = null;
IndexReader ireader = null;
IndexSearcher isearcher = null;
try {
    //建立内存索引对象
    directory = new RAMDirectory();     

    //配置IndexWriterConfig
    IndexWriterConfig iwConfig = new IndexWriterConfig(Version.LUCENE_34 , analyzer);
    iwConfig.setOpenMode(OpenMode.CREATE_OR_APPEND);
    iwriter = new IndexWriter(directory , iwConfig);
    //写入索引
    Document doc = new Document();
    doc.add(new Field("ID", "10000", Field.Store.YES, Field.Index.NOT_ANALYZED));
    doc.add(new Field(fieldName, text, Field.Store.YES, Field.Index.ANALYZED));
    iwriter.addDocument(doc);
    iwriter.close();

    //搜索过程**********************************
    //实例化搜索器   
    ireader = IndexReader.open(directory);
    isearcher = new IndexSearcher(ireader);            

    String keyword = "iPhone5s土豪金";            
    //使用QueryParser查询分析器构造Query对象
    QueryParser qp = new QueryParser(Version.LUCENE_34, fieldName, analyzer);
    qp.setDefaultOperator(QueryParser.AND_OPERATOR);
    Query query = qp.parse(keyword);
    System.out.println("Query = " + query);

    //搜索相似度最高的5条记录
    TopDocs topDocs = isearcher.search(query , 5);
    System.out.println("命中:" + topDocs.totalHits);
    //输出结果
    ScoreDoc[] scoreDocs = topDocs.scoreDocs;
    for (int i = 0; i < topDocs.totalHits; i++){
        Document targetDoc = isearcher.doc(scoreDocs[i].doc);
        System.out.println("内容:" + targetDoc.toString());
    }

} catch (CorruptIndexException e) {
    e.printStackTrace();
} catch (LockObtainFailedException e) {
    e.printStackTrace();
} catch (IOException e) {
    e.printStackTrace();
} catch (ParseException e) {
    e.printStackTrace();
} finally{
    if(ireader != null){
        try {
            ireader.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    if(directory != null){
        try {
            directory.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

执行结果:

加载扩展词典:ext.dic
加载扩展停止词典:stopword.dic
Query = text:iphone5s土豪金
命中:1
内容:Document<stored,indexed<ID:10000> stored,indexed,tokenized<text:据说WWDC要推出iPhone6要出了?与iPhone5s土豪金相比怎样呢?>>
直接通过Analyzer进行分词

如果我们不需要建立Lucene索引文件,而是单纯的对一段文本进行分词,可以直接创建一个org.apache.lucene.analysis.Analyzer分词对象(org.wltea.analyzer.lucene.IKAnalyzer IK分词主类,基于Lucene的Analyzer接口实现)进行遍历分词数据。

下面演示下,并且在分词之前额外的添加一些单词到字典中。ext.dic词典如下:

iPhone5s土豪金
2014巴西世界杯

代码如下:

// 检索内容
String text = "据说WWDC要推出iPhone6要出了?与iPhone5s土豪金相比怎样呢?@2014巴西世界杯 test中文";
List<String> list = new ArrayList<String>();
list.add("test中文");

// 尚未初始化,因为第一次执行分词的时候才会初始化,为了在执行分此前手动添加额外的字典,需要先手动的初始化一下
Dictionary.initial(DefaultConfig.getInstance());
Dictionary.getSingleton().addWords(list);

//创建分词对象  
Analyzer analyzer = new IKAnalyzer(true);       
StringReader reader = new StringReader(text);  

TokenStream ts = analyzer.tokenStream("", reader);  
CharTermAttribute term = ts.getAttribute(CharTermAttribute.class);  
//遍历分词数据  
try {
    while(ts.incrementToken()){  
        System.out.print(term.toString()+"|");  
    }
} catch (IOException e) {
    e.printStackTrace();
} finally{
    reader.close();
}

执行结果:

加载扩展词典:ext.dic
加载扩展停止词典:stopword.dic
据说|wwdc|要|推出|iphone6|要|出了|与|iphone5s土豪金|相比|怎样|呢|2014巴西世界杯|test中文|
使用IKSegmenter进行分词

另外,如果想不结合Lucene(不使用lucene-core-3.6.0.jar),而是仅仅单独的使用IKAnalyzer,可以直接使用IK分词器的核心类,真正分词的实现类IKSegmenter分词器进行分词,代码如下:

// 单独使用
// 检索内容
String text = "据说WWDC要推出iPhone6要出了?与iPhone5s相比怎样呢?@2014巴西世界杯";

// 创建分词对象  
StringReader reader = new StringReader(text);

IKSegmenter ik = new IKSegmenter(reader,true);// 当为true时,分词器进行最大词长切分
Lexeme lexeme = null;
try {
    while((lexeme = ik.next())!=null)
        System.out.println(lexeme.getLexemeText());
} catch (IOException e) {
    e.printStackTrace();
} finally{
    reader.close();
}
性能测试:

检测目标:在单独使用IKAnalyzer的情况下,尽量往扩展字典添加词组,测试十几万长度的文本的分词效率。

扩展词库添加搜狗词库:

http://pinyin.sogou.com/dict/cell.php?id=11640
词条 大小 检索内容字数
392790个 13737KB 158453

代码如下:

// 计算载入字典时间
long startLoadDict = System.currentTimeMillis();
Dictionary.initial(DefaultConfig.getInstance());
long endLoadDict = System.currentTimeMillis();

// 创建分词对象  
StringReader reader = new StringReader(text);
Lexeme lexeme = null;
int hintTimes = 0;
IKSegmenter ik = new IKSegmenter(reader,true);// 当为true时,分词器进行最大词长切分
long start = System.currentTimeMillis();
try {
    while((lexeme = ik.next())!=null)
        hintTimes ++;
} catch (IOException e) {
    e.printStackTrace();
} finally{
    reader.close();
}
long end = System.currentTimeMillis();
System.out.println("载入字典时间:" + (endLoadDict - startLoadDict)/1000.0);
System.out.println("处理文本字数:" + text.length());
System.out.println("获取词元次数:" + hintTimes);
System.out.println("执行总时间:" + (end - start)/1000.0 + "s");
System.out.println("处理速度:" + text.length() / ((end - start)/1000.0) + "字/秒");
System.out.println("本次获取词元速度:" + hintTimes / ((end - start)/1000.0) + "词/秒");

IKAnalyzer本身有27W的词库,加上扩展词典,经过优化的方式存储到内存空间中的。

结果:

加载扩展词典:ext.dic
加载扩展停止词典:stopword.dic
载入字典时间:2.51
处理文本字数:158453
获取词元次数:54424
执行总时间:0.46s
处理速度:344463.04347826086字/秒
本次获取词元速度:118313.04347826086词/秒
除了文章中有特别说明,均为IT宅原创文章,转载请以链接形式注明出处。
本文链接:http://www.itzhai.com/ikanalyzer-lucene-demo-performance-test.html
关键字: , ,
arthinking Java技术交流群:280755654,入门群:428693174 more
分享到:
 
2014 6/2
如果您有更好的原创技术博文或者观点,欢迎投稿:admin@itzhai.com,或者关注订阅左侧浮动面板的微信号订阅IT宅itread)发送消息。
文章评论
    3条评论
  1. 擦~ 2014年11月13日12:34:05  #-49楼 回复 回复

    long start = System.currentTimeMillis();你写的不是地方

  2. yhmpianzi 2015年04月10日16:33:57  #-48楼 回复 回复

    怎么只使用外部词典而不适用自带的词典呢

给我留言

有人回复时邮件通知我
J2EE的相关文章
随机文章 本月热门 热评
1 ubuntu下安装Bochs虚拟机的方法及其可能遇到的make问题 2011/4/29
2 追逐梦想的步伐 SMART目标和实用投资计划(PIP) 2012/8/4
3 EXT的核心组件,相关的处理事件和类的使用 2011/7/24
4 使用JSTL格式化从服务器获取的Date类型数据 2011/9/7
5 需要有的一种热血职人精神 2013/12/27
6 JavaScript设计模式笔记 – 单例模式 链式调用 2012/10/25
友情推荐 更多
破博客 文官洗碗安天下,武将打怪定乾坤。多么美好的年代,思之令人泪落。
Mr.5's Life 白天是一名程序员,晚上就是个有抱负的探索者
行知-追寻技术之美 关注大数据,分布式系统
我爱编程 编程成长轨迹
Cynthia's Blog 学习笔记 知识总结 思考感悟
 
猜您喜欢
欢迎关注我的公众号 IT宅
关于IT宅 文章归档

IT宅中的文章除了标题注明转载或有特别说明的文章,均为IT宅的技术知识总结,学习笔记或随笔。如果喜欢,请使用文章下面提供的分享组件。转载请注明出处并加入文章的原链接。 感谢大家的支持。

联系我们:admin@itzhai.com

Theme by arthinking. Copyright © 2011-2015 IT宅.com 保留所有权利.