2.7、Lucene新闻高频词提取


2.7.1、问题提出

2.7.2、需求分析

2.7.3、编程实现

-———————————————-

2.7.1、问题提出

统计 一篇新闻文档,统计出现频率最高的哪些词语

2.7.2、需求分析

文本关键词提取算法、开源工具很多

本文:《从Lucene索引中 提取 词项频率Top N》

词条化:从文本中 去除 标点、停用词等;

索引过程的本质:词条化 生成 倒排索引的过程;

代码思路:IndexReader的getTermVector获取文档的某一个字段 Terms,从 terms 中获取 tf(term frequency),拿到词项的 tf 以后,放到map中 降序排序,取出 Top-N.

2.7.3、编程实现

网上找到新闻稿《李开复:无人驾驶进入黄金时代 AI有巨大投资机会》,放在 testfile/news.txt 文件中。

对 testfile/news.txt 生成索引:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
package com.learn.lucene.chapter2.highfrequency;

import com.learn.lucene.chapter2.ik.IKAnalyzer8x;
import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field;
import org.apache.lucene.document.FieldType;
import org.apache.lucene.index.IndexOptions;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.IndexWriterConfig;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.FSDirectory;

import java.io.*;
import java.nio.file.Paths;

/**
* 2.7.1、问题提出
* 统计 一篇新闻文档,统计出现频率最高的哪些词语
* 2.7.2、需求分析
* 文本关键词提取算法、开源工具很多
* 本文:《从Lucene索引中 提取 词项频率Top N》
* 词条化:从文本中 去除 标点、停用词等;
* 索引过程的本质:词条化 生成 倒排索引的过程;
* 代码思路:IndexReader的getTermVector获取文档的某一个字段 Terms,从 terms 中获取 tf(term frequency),拿到词项的 tf 以后,放到map中 降序排序,取出 Top-N.
* 2.7.3、编程实现
* 网上找到新闻稿《李开复:无人驾驶进入黄金时代 AI有巨大投资机会》,放在 testfile/news.txt 文件中。
*
* 索引文档
*/
public class IndexDocs {

public static void main(String[] args) throws IOException {
File newfile = new File("testfile/news.txt");
String text1 = textToString(newfile);
Analyzer smcAnalyzer = new IKAnalyzer8x(true);
IndexWriterConfig indexWriterConfig = new IndexWriterConfig(smcAnalyzer);
indexWriterConfig.setOpenMode(IndexWriterConfig.OpenMode.CREATE);
// 索引的存储路径
Directory directory = FSDirectory.open(Paths.get("indexdir"));
// 索引的增删改由 IndexWriter 创建
IndexWriter indexWriter = new IndexWriter(directory, indexWriterConfig);
// 新建 FieldType,用于指定字段索引时的信息
FieldType type = new FieldType();
type.setIndexOptions(IndexOptions.DOCS_AND_FREQS_AND_POSITIONS_AND_OFFSETS);
type.setStored(true); // 原始字符串全部被保存在索引中
type.setStoreTermVectors(true); // 存储词项 量
type.setTokenized(true); // 词条化
Document doc1 = new Document();
Field field1 = new Field("content", text1, type);
doc1.add(field1);
indexWriter.addDocument(doc1);
indexWriter.close();
directory.close();

}

public static String textToString(File file) {
StringBuilder result = new StringBuilder();
try {
// 构造一个 BufferedReader 类来读取文件
BufferedReader bufferedReader = new BufferedReader(new FileReader(file));
String str = null;
// 使用 readline 方法,一次读一行
while (null != (str = bufferedReader.readLine())) {
result.append(System.lineSeparator() + str);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return result.toString();
}

}

运行。

提取高频词:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
package com.learn.lucene.chapter2.highfrequency;

import org.apache.lucene.index.DirectoryReader;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.index.Terms;
import org.apache.lucene.index.TermsEnum;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.FSDirectory;
import org.apache.lucene.util.BytesRef;

import java.io.IOException;
import java.nio.file.Paths;
import java.util.*;

/**
* 提取高频词
*/
public class GetTopTerms {
public static void main(String[] args) throws IOException {
Directory directory = FSDirectory.open(Paths.get("indexdir"));
IndexReader reader = DirectoryReader.open(directory);
// 因为之索引了一个文档,所以DocID为0
// 通过 getTermVector 获取 content 字段的词项
Terms terms = reader.getTermVector(0, "content");
// 遍历词项
TermsEnum termsEnum = terms.iterator();
Map<String, Integer> map = new HashMap<String, Integer>();
BytesRef thisTerm;
while (null != (thisTerm = termsEnum.next())) {
String termText = thisTerm.utf8ToString(); // 词项
// 通过 totalTermFreq() 方法获取词项频率
map.put(termText, (int) termsEnum.totalTermFreq());
}
// 按 value 排序
List<Map.Entry<String, Integer>> sortedMap = new ArrayList<>(map.entrySet());
Collections.sort(sortedMap, new Comparator<Map.Entry<String, Integer>>() {
@Override
public int compare(Map.Entry<String, Integer> o1, Map.Entry<String, Integer> o2) {
return (o2.getValue() - o1.getValue());
}
});

getTopN(sortedMap, 10);
}

public static void getTopN(List<Map.Entry<String, Integer>> sortedMap, int N) {
for (int i = 0; i < N; i++) {
System.out.println(sortedMap.get(i).getKey() + ":" + sortedMap.get(i).getValue());
}
}
}