- 从Lucene到Elasticsearch:全文检索实战
- 姚攀
- 1061字
- 2020-11-28 14:50:07
2.7 Lucene新闻高频词提取
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文件中,索引文档代码见代码清单2-13。
代码清单2-13
import java.io.BufferedReader; import java.io.File; import java.io.FileReader; import java.io.IOException; import java.nio.file.Paths; 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.index.IndexWriterConfig.OpenMode; import org.apache.lucene.store.Directory; import org.apache.lucene.store.FSDirectory; import lucene.ik.IKAnalyzer6x; public class IndexDocs { public static void main(String[] args)throws IOException { File newsfile = new File("testfile/lucene.txt"); String text1 = textToString(newsfile); Analyzer smcAnalyzer = new IKAnalyzer6x(true); IndexWriterConfig indexWriterConfig = new IndexWriterConfig( smcAnalyzer); indexWriterConfig.setOpenMode(OpenMode.CREATE); // 索引的存储路径 Directory directory = null; // 索引的增删改由indexWriter创建 IndexWriter indexWriter = null; directory = FSDirectory.open(Paths.get("indexdir")); 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 br = new BufferedReader(new FileReader(file)); String str = null; // 使用readLine方法,一次读一行 while ((str = br.readLine()) != null) { result.append(System.lineSeparator()+ str); } br.close(); } catch(Exception e){ e.printStackTrace(); } return result.toString(); } }
获取新闻热词的代码见代码清单2-14。
代码清单2-14
import java.io.IOException; import java.nio.file.Paths; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; 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; 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((thisTerm=termsEnum.next())! = null){ String termText = thisTerm.utf8ToString(); // 词项 // 通过totalTermFreq()方法获取词项频率 map.put(termText,(int)termsEnum.totalTermFreq()); } // 按value排序 List<Map.Entry<String, Integer>> sortedMap = new ArrayList<Map.Entry<String, Integer>>(map.entrySet()); Collections.sort(sortedMap, new Comparator<Map.Entry< String, Integer>>(){ public int compare(Map.Entry<String, Integer> o1, Map. Entry<String, Integer> o2) { return(o2.getValue()- o1.getValue()); } }); getTopN(sortedMap, 10); } // 获取top-n public static void getTopN(List<Entry<String, Integer>> sortedMap, int N){ for(int i = 0; i < N; i++){ System.out.println(sortedMap.get(i).getKey()+ ":" + sortedMap.get(i).getValue()); } } }
运行结果:
人工智能:61 领域:34 公司:23 无人驾驶:20 投资:20 互联网:18 创业:17 中国:16 特别:16 技术:15