【Lucene3.6.2入门系列】第01节_HelloWord

x33g5p2x  于2021-12-24 转载在 其他  
字(6.6k)|赞(0)|评价(0)|浏览(368)

完整版见 https://jadyer.github.io/2013/08/18/lucene-demo/

  1. package com.jadyer.lucene;
  2. import java.io.File;
  3. import java.io.FileReader;
  4. import java.io.IOException;
  5. import org.apache.lucene.analysis.standard.StandardAnalyzer;
  6. import org.apache.lucene.document.Document;
  7. import org.apache.lucene.document.Field;
  8. import org.apache.lucene.index.IndexReader;
  9. import org.apache.lucene.index.IndexWriter;
  10. import org.apache.lucene.index.IndexWriterConfig;
  11. import org.apache.lucene.queryParser.QueryParser;
  12. import org.apache.lucene.search.IndexSearcher;
  13. import org.apache.lucene.search.Query;
  14. import org.apache.lucene.search.ScoreDoc;
  15. import org.apache.lucene.search.TopDocs;
  16. import org.apache.lucene.store.Directory;
  17. import org.apache.lucene.store.FSDirectory;
  18. import org.apache.lucene.util.Version;
  19. /**
  20. * 【Lucene3.6.2入门系列】第01节_HelloWord
  21. * @see 这里只需用到一个lucene-core-3.6.2.jar
  22. * @see Lucene官网:http://lucene.apache.org
  23. * @see Lucene下载:http://archive.apache.org/dist/lucene/java/
  24. * @see Lucene文档:http://wiki.apache.org/lucene-java/
  25. * @see -------------------------------------------------------------------------------------------------------------
  26. * @see 1)对于全文搜索工具,都是由索引、分词、搜索三部分组成
  27. * @see 2)被存储和被索引,是两个独立的概念
  28. * @see -------------------------------------------------------------------------------------------------------------
  29. * @see 域的存储选项
  30. * @see Field.Store.YES--会把该域中的内容存储到文件中,方便进行文本的还原
  31. * @see Field.Store.NO---表示该域中的内容不存储到文件中,但允许被索引,且内容无法完全还原(doc.get("##"))
  32. * @see -------------------------------------------------------------------------------------------------------------
  33. * @see 域的索引选项
  34. * @see Field.Index.ANALYZED----------------进行分词和索引,适用于标题、内容等
  35. * @see Field.Index.NOT_ANALYZED------------进行索引但不分词(如身份证号、姓名、ID等),适用于精确搜索
  36. * @see Field.Index.ANALYZED_NOT_NORMS------进行分词但是不存储norms信息,这个norms中包括了创建索引的时间和权值等信息
  37. * @see Field.Index.NOT_ANALYZED_NOT_NORMS--即不进行分词也不存储norms信息
  38. * @see Field.Index.NO----------------------不进行索引
  39. * @see norms:当数据被搜索出来后,便涉及到排序的问题,而排序是有一些评分规则的,于是NORMS中就存储了这些排序的信息
  40. * @see -------------------------------------------------------------------------------------------------------------
  41. * @see 域选项最佳实践
  42. * @see Field.Store Field.Index 域值
  43. * @see YES NOT_ANALYZED_NOT_NORMS 标识符(主键、文件名),电话号码,身份证号,姓名,日期
  44. * @see YES ANALYZED 文档标题和摘要
  45. * @see NO ANALYZED 文档正文
  46. * @see NO NOT_ANALYZED 隐藏关键字
  47. * @see YES NO 文档类型,数据库主键(不进行索引)
  48. * @see -------------------------------------------------------------------------------------------------------------
  49. * @create Jun 29, 2012 4:20:19 PM
  50. * @author 玄玉<http://blog.csdn.net/jadyer>
  51. */
  52. public class HelloWord {
  53. private static final String PATH_OF_FILE = "myExample/01_file/"; //待索引文件的目录
  54. private static final String PATH_OF_INDEX = "myExample/01_index/"; //存放索引文件的目录
  55. /**
  56. * 创建索引
  57. * @see ---------------------------------------------------------------------------------------------------------
  58. * @see 1、创建Directory-----------------指定索引被保存的位置
  59. * @see 2、创建IndexWriter---------------通过IndexWriter写索引
  60. * @see 3、创建Document对象---------------我们索引的有可能是一段文本or数据库中的一张表
  61. * @see 4、为Document添加Field------------相当于Document的标题、大小、内容、路径等等,二者类似于数据库表中每条记录和字段的关系
  62. * @see 5、通过IndexWriter添加文档到索引中
  63. * @see 6、关闭IndexWriter----------------用完IndexWriter之后,必须关闭之
  64. * @see ---------------------------------------------------------------------------------------------------------
  65. * @see _0.fdt和_0.fdx文件--保存域中所存储的数据(Field.Store.YES条件下的)
  66. * @see _0.fnm文件----------保存域选项的数据(即new Field(name, value)中的name)
  67. * @see _0.frq文件----------记录相同的文件(或查询的关键字)出现的次数,它是用来做评分和排序的
  68. * @see _0.nrm文件----------存储一些评分信息
  69. * @see _0.prx文件----------记录偏移量
  70. * @see _0.tii和_0.tis文件--存储索引里面的所有内容信息
  71. * @see segments_1文件------它是段文件,Lucene首先会到段文件中查找相应的索引信息
  72. * @see ---------------------------------------------------------------------------------------------------------
  73. */
  74. public void createIndex(){
  75. Directory directory = null;
  76. IndexWriter writer = null;
  77. Document doc = null;
  78. try{
  79. //FSDirectory会根据当前的运行环境打开一个合理的基于File的Directory(若在内存中创建索引则new RAMDirectory())
  80. //这里是在硬盘上"D:/OS_Folder/Desktop/luceneDemo/index01/"文件夹中创建索引
  81. directory = FSDirectory.open(new File(PATH_OF_INDEX));
  82. //由于Lucene2.9之后,其索引的格式就不会再兼容Lucene的所有版本了,所以在创建索引前,要指定其所匹配的Lucene版本号
  83. //这里通过IndexWriterConfig()构造方法的Version.LUCENE_36参数值指明索引所匹配的版本号,并使用了Lucene的标准分词器
  84. writer = new IndexWriter(directory, new IndexWriterConfig(Version.LUCENE_36, new StandardAnalyzer(Version.LUCENE_36)));
  85. for(File file : new File(PATH_OF_FILE).listFiles()){
  86. doc = new Document();
  87. //把内容添加到索引域中,即为该文档存储信息,供将来搜索时使用(下面的写法,其默认为Field.Store.NO和Field.Index.ANALYZED)
  88. //如果我们想把content的内容也存储到硬盘上,那就需要先把file转换成字符串,然后按照"fileName"的存储方式加到Field中
  89. //我们可以用commons-io-2.3.jar提供的FileUtils.readFileToString(file),这是很方便的工具包,有了它几乎都不用手写任何的IO方法了
  90. //doc.add(new Field("content", FileUtils.readFileToString(file), Field.Store.YES, Field.Index.ANALYZED));
  91. doc.add(new Field("content", new FileReader(file)));
  92. //Field.Store.YES-----------这里是将文件的全名存储到硬盘中
  93. //Field.Index.NOT_ANALYZED--这里是不对文件名进行分词
  94. doc.add(new Field("fileName", file.getName(), Field.Store.YES, Field.Index.NOT_ANALYZED));
  95. doc.add(new Field("filePath", file.getAbsolutePath(), Field.Store.YES, Field.Index.NOT_ANALYZED));
  96. //通过IndexWriter添加文档到索引中
  97. writer.addDocument(doc);
  98. }
  99. }catch(Exception e){
  100. System.out.println("创建索引的过程中遇到异常,堆栈轨迹如下");
  101. e.printStackTrace();
  102. }finally{
  103. if(null != writer){
  104. try {
  105. writer.close(); //IndexWriter在用完之后一定要关闭
  106. } catch (IOException ce) {
  107. System.out.println("关闭IndexWriter时遇到异常,堆栈轨迹如下");
  108. ce.printStackTrace();
  109. }
  110. }
  111. }
  112. }
  113. /**
  114. * 搜索文件
  115. * @see 1、创建Directory
  116. * @see 2、创建IndexReader
  117. * @see 3、根据IndexReader创建IndexSearcher
  118. * @see 4、创建搜索的Query
  119. * @see 5、根据searcher搜索并返回TopDocs
  120. * @see 6、根据TopDocs获取ScoreDoc对象
  121. * @see 7、根据searcher和ScoreDoc对象获取具体的Document对象
  122. * @see 8、根据Document对象获取需要的值
  123. * @see 9、关闭IndexReader
  124. */
  125. public void searchFile(){
  126. IndexReader reader = null;
  127. try{
  128. reader = IndexReader.open(FSDirectory.open(new File(PATH_OF_INDEX)));
  129. IndexSearcher searcher = new IndexSearcher(reader);
  130. //创建基于Parser搜索的Query,创建时需指定其"搜索的版本,默认搜索的域,分词器"....这里的域指的是创建索引时Field的名字
  131. QueryParser parser = new QueryParser(Version.LUCENE_36, "content", new StandardAnalyzer(Version.LUCENE_36));
  132. Query query = parser.parse("java"); //指定==>搜索域为content(即上一行代码指定的"content")中包含"java"的文档
  133. TopDocs tds = searcher.search(query, 10); //第二个参数指定搜索后显示的条数,若查到5条则显示为5条,查到15条则只显示10条
  134. ScoreDoc[] sds = tds.scoreDocs; //TopDocs中存放的并不是我们的文档,而是文档的ScoreDoc对象
  135. for(ScoreDoc sd : sds){ //ScoreDoc对象相当于每个文档的ID号,我们就可以通过ScoreDoc来遍历文档
  136. Document doc = searcher.doc(sd.doc); //sd.doc得到的是文档的序号
  137. System.out.println(doc.get("fileName") + "[" + doc.get("filePath") + "]"); //输出该文档所存储的信息
  138. }
  139. }catch(Exception e){
  140. System.out.println("搜索文件的过程中遇到异常,堆栈轨迹如下");
  141. e.printStackTrace();
  142. }finally{
  143. if(null != reader){
  144. try {
  145. reader.close();
  146. } catch (IOException e) {
  147. System.out.println("关闭IndexReader时遇到异常,堆栈轨迹如下");
  148. e.printStackTrace();
  149. }
  150. }
  151. }
  152. }
  153. }

测试时,要在myExample/01_file/文件夹中准备几个包含内容的文件(比如txt格式的)

然后先执行createIndex()方法,再执行searchFile()方法,最后观看控制台输出即可

相关文章