这应该是我第二次写IK中文分词的相关东西了。话说IK真心好用,最开始就用过IK的搜索后来又用它和solr结合使用。
关于IK可以参考下官方文档的介绍,使用配置也有相关的pdf文档。http://www.oschina.net/p/ikanalyzer
今天仅仅使用到了IK的分词功能。所以代码很简单,我就直接贴上来了。
这个代码主要是对传入的参数进行分词,并统计好每个次的频率。代码如下:
01 | public static Map getTextDef(String text) throws IOException { |
02 | Map<String, Integer> wordsFren= new HashMap<String, Integer>(); |
03 | IKSegmenter ikSegmenter = new IKSegmenter( new StringReader(text), true ); |
04 | Lexeme lexeme; |
05 | while ((lexeme = ikSegmenter.next()) != null ) { |
06 | if (lexeme.getLexemeText().length()> 1 ){ |
07 | if (wordsFren.containsKey(lexeme.getLexemeText())){ |
08 | wordsFren.put(lexeme.getLexemeText(),wordsFren.get(lexeme.getLexemeText())+ 1 ); |
09 | } else { |
10 | wordsFren.put(lexeme.getLexemeText(), 1 ); |
11 | } |
12 | } |
13 | } |
14 | return wordsFren; |
15 | } |
代码很简单,主要介绍下IK中的类,IKSegmenter是分词的主要类,其参数分别是分词的句子或者文章,后面的参数是是否开启智能模式,不开启就按最小词义分。
分词的结果是Lexeme这个类,用其中的getLexemeText()方法就能取出相关的分词结果。
接下来是计算词频,将分词结果和出现次数放到一个map结构中,map的value对应了词的出现次数。这里注意一下,我只记录两个字及两个字以上的分词结果。
01 | public static void sortSegmentResult(Map<String,Integer> wordsFrenMaps, int topWordsCount){ |
02 | System.out.println( "排序前:================" ); |
03 | Iterator<Map.Entry<String,Integer>> wordsFrenMapsIterator=wordsFrenMaps.entrySet().iterator(); |
04 | while (wordsFrenMapsIterator.hasNext()){ |
05 | Map.Entry<String,Integer> wordsFrenEntry=wordsFrenMapsIterator.next(); |
06 | System.out.println(wordsFrenEntry.getKey()+ " 的次数为" +wordsFrenEntry.getValue()); |
07 | } |
08 |
09 | List<Map.Entry<String, Integer>> wordFrenList = new ArrayList<Map.Entry<String, Integer>>(wordsFrenMaps.entrySet()); |
10 | Collections.sort(wordFrenList, new Comparator<Map.Entry<String, Integer>>() { |
11 | public int compare(Map.Entry<String, Integer> obj1, Map.Entry<String, Integer> obj2) { |
12 | return obj2.getValue() - obj1.getValue(); |
13 | } |
14 | }); |
15 | System.out.println( "排序后:================" ); |
16 | for ( int i= 0 ;i<topWordsCount&&i<wordFrenList.size();i++){ |
17 | Map.Entry<String,Integer> wordFrenEntry=wordFrenList.get(i); |
18 | if (wordFrenEntry.getValue()> 1 ){ |
19 | System.out.println(wordFrenEntry.getKey()+ " 的次数为" +wordFrenEntry.getValue()); |
20 | } |
21 | } |
22 | } |
这个方法主要对分词结果及词频按照出现次数排序,没有自己去写实现,主要借用了collections的sort方法。
测试方法如下:
01 | public static void main(String args[]) throws IOException { |
02 |
03 | String text = "IKAnalyzer是一个开源的,基于java语言开发的轻量级的中文分词工具包。从2006年12月推出1.0版开始,IKAnalyzer已经推出 了3个大版本。最初,它是以开源项目 Lucene为应用主体的,结合词典分词和文法分析算法的中文分词组件。新版本的IKAnalyzer3.0则发展为 面向Java的公用分词组件,独立于Lucene项目,同时提供了对Lucene的默认优化实现。\n" + |
04 | "\n" + |
05 | "IKAnalyzer3.0特性:\n" + |
06 | "\n" + |
07 | "采用了特有的“正向迭代最细粒度切分算法“,具有60万字/秒的高速处理能力。\n" + |
08 | "\n" + |
09 | "采用了多子处理器分析模式,支持:英文字母(IP地址、Email、URL)、数字(日期,常用中文数量词,罗马数字,科学计数法),中文词汇(姓名、地名处理)等分词处理。\n" + |
10 | "\n" + |
11 | "优化的词典存储,更小的内存占用。支持用户词典扩展定义\n" + |
12 | "\n" + |
13 | "针对Lucene全文检索优化的查询分析器IKQueryParser(作者吐血推荐);采用歧义分析算法优化查询关键字的搜索排列组合,能极大的提高Lucene检索的命中率。" ; |
14 | int topWordsCount= 3 ; |
15 | Map<String,Integer> wordsFrenMaps=getTextDef(text); |
16 | sortSegmentResult(wordsFrenMaps,topWordsCount); |
17 |
18 |
19 | } |
01 | 加载扩展词典:ikdict/ext.dic |
02 | 加载扩展停止词典:ikdict/english_stopword.dic |
03 | 加载扩展停止词典:ikdict/chinese_stopword.dic |
04 | 排序前:================ |
05 | ikanalyzer3.0 的次数为2 |
06 | 开源 的次数为2 |
07 | 开发 的次数为1 |
08 | 姓名 的次数为1 |
09 | lucene 的次数为5 |
10 | 内存 的次数为1 |
11 | 词汇 的次数为1 |
12 | 支持 的次数为2 |
13 | 英文字母 的次数为1 |
14 | 查询 的次数为2 |
15 | 面向 的次数为1 |
16 | 采用 的次数为1 |
17 | 12月 的次数为1 |
18 | 推荐 的次数为1 |
19 | ikanalyzer 的次数为2 |
20 | 地名 的次数为1 |
21 | 默认 的次数为1 |
22 | 提供 的次数为1 |
23 | 特性 的次数为1 |
24 | 地址 的次数为1 |
25 | 中文 的次数为4 |
26 | 文法 的次数为1 |
27 | 组件 的次数为2 |
28 | 新版本 的次数为1 |
29 | 吐血 的次数为1 |
30 | 检索 的次数为2 |
31 | 全文 的次数为1 |
32 | 常用 的次数为1 |
33 | 公用 的次数为1 |
34 | 分析器 的次数为1 |
35 | 项目 的次数为2 |
36 | 存储 的次数为1 |
37 | 数量词 的次数为1 |
38 | 处理器 的次数为1 |
39 | 工具包 的次数为1 |
40 | 占用 的次数为1 |
41 | 计数 的次数为1 |
42 | 分析 的次数为3 |
43 | 版本 的次数为1 |
44 | 正向 的次数为1 |
45 | url 的次数为1 |
46 | 用了 的次数为2 |
47 | 迭代 的次数为1 |
48 | 搜索 的次数为1 |
49 | 模式 的次数为1 |
50 | email 的次数为1 |
51 | 关键字 的次数为1 |
52 | 日期 的次数为1 |
53 | 扩展 的次数为1 |
54 | 提高 的次数为1 |
55 | ikqueryparser 的次数为1 |
56 | 能力 的次数为1 |
57 | 3个 的次数为1 |
58 | 词典 的次数为3 |
59 | 排列组合 的次数为1 |
60 | 更小 的次数为1 |
61 | 定义 的次数为1 |
62 | 科学 的次数为1 |
63 | 高速 的次数为1 |
64 | 轻量级 的次数为1 |
65 | 优化 的次数为4 |
66 | 细粒度 的次数为1 |
67 | 2006年 的次数为1 |
68 | 发展为 的次数为1 |
69 | 多子 的次数为1 |
70 | 命中率 的次数为1 |
71 | 立于 的次数为1 |
72 | 数字 的次数为1 |
73 | 万字 的次数为1 |
74 | 60 的次数为1 |
75 | 特有 的次数为1 |
76 | 罗马数字 的次数为1 |
77 | 推出 的次数为2 |
78 | 用户 的次数为1 |
79 | 1.0版 的次数为1 |
80 | ip 的次数为1 |
81 | 算法 的次数为3 |
82 | 分词 的次数为5 |
83 | 歧义 的次数为1 |
84 | 作者 的次数为1 |
85 | java 的次数为2 |
86 | 语言 的次数为1 |
87 | 主体 的次数为1 |
88 | 最初 的次数为1 |
89 | 切分 的次数为1 |
90 | 排序后:================ |
91 | lucene 的次数为5 |
92 | 分词 的次数为5 |
93 | 中文 的次数为4 |
这里面要注意一下,IK本身有一个文件叫IKAnalyzer.cfg.xml
这个文件可以自己配置词典,词典有两种分别是ext_dict及ext_stopwords,其中ext_dict主要定义了一些关键字,这些关键字不会被分词分开,ext_stopwords主要配置停止词,什么是停止词呢?比如“的”,“得”,“我”这些没有具体意义但是又出现特别多的词就不应该作为关键字词出现,所以在分词的时候要把这些词过滤掉。
1 | < properties > |
2 | < comment >IK Analyzer 扩展配置</ comment > |
3 | <!--用户可以在这里配置自己的扩展字典--> |
4 | < entry key = "ext_dict" >ikdict/ext.dic;</ entry > |
5 |
6 | <!--用户可以在这里配置自己的扩展停止词字典--> |
7 | < entry key = "ext_stopwords" >ikdict/english_stopword.dic;ikdict/chinese_stopword.dic</ entry > |
8 |
9 | </ properties > |
但是OSC好像没有附件可以传。。。放到代码分享中了,用的自取,http://www.oschina.net/code/snippet_195637_22628
其中中文停止词4545个,英文停止词1434个,数据库相关词汇1692个。
总结一下,最近正在研究关键字及摘要自动生成,这里主要介绍了使用IK分词并统计词频,并分享了相关的词典。但是计算关键字单靠这样的分词统计词频还是不管用的,最近在研究TFIDF算法,后面实现成功了再和大家分享一下。