lucene第一步,lucene基础,索引创建

本文详细介绍了Lucene全文检索技术的基本概念、工程结构、索引创建时的属性、lucene的增删改查类以及如何进行单元测试,涵盖了从理论到实践的全面指导。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

出自:http://blog.youkuaiyun.com/wxwzy738/article/details/8799184 的整理


1、工程结构


2、索引创建时的属性:

Field.Store.YES或者NO(存储域选项)
设置为YES表示或把这个域中的内容完全存储到文件中,方便进行文本的还原
设置为NO表示把这个域的内容不存储到文件中,但是可以被索引,此时内容无法完全还原(doc.get)

Field.Index(索引选项)
Index.ANALYZED:进行分词和索引,适用于标题、内容等
Index.NOT_ANALYZED:进行索引,但是不进行分词,如果身份证号,姓名,ID等,适用于精确搜索
Index.ANALYZED_NOT_NORMS:进行分词但是不存储norms信息,这个norms中包括了创建索引的时间和权值等信息
norms中存储了很多排序的信息,
Index.NOT_ANALYZED_NOT_NORMS:即不进行分词也不存储norms信息
Index.NO:不进行索引

3、lucene的增删改查类

  1. packageorg.itat.index;
  2. importjava.io.IOException;
  3. importjava.text.ParseException;
  4. importjava.text.SimpleDateFormat;
  5. importjava.util.Date;
  6. importjava.util.HashMap;
  7. importjava.util.Map;
  8. importorg.apache.lucene.analysis.standard.StandardAnalyzer;
  9. importorg.apache.lucene.document.Document;
  10. importorg.apache.lucene.document.Field;
  11. importorg.apache.lucene.document.NumericField;
  12. importorg.apache.lucene.index.CorruptIndexException;
  13. importorg.apache.lucene.index.IndexReader;
  14. importorg.apache.lucene.index.IndexWriter;
  15. importorg.apache.lucene.index.IndexWriterConfig;
  16. importorg.apache.lucene.index.StaleReaderException;
  17. importorg.apache.lucene.index.Term;
  18. importorg.apache.lucene.search.IndexSearcher;
  19. importorg.apache.lucene.search.ScoreDoc;
  20. importorg.apache.lucene.search.TermQuery;
  21. importorg.apache.lucene.search.TopDocs;
  22. importorg.apache.lucene.store.Directory;
  23. importorg.apache.lucene.store.LockObtainFailedException;
  24. importorg.apache.lucene.store.RAMDirectory;
  25. importorg.apache.lucene.util.Version;
  26. publicclassIndexUtil{
  27. privateString[]ids={"1","2","3","4","5","6"};
  28. privateString[]emails={"aa@itat.org","bb@itat.org","cc@cc.org","dd@sina.org","ee@zttc.edu","ff@itat.org"};
  29. privateString[]contents={
  30. "welcometovisitedthespace,Ilikebook",
  31. "helloboy,Ilikepingpengball",
  32. "mynameisccIlikegame",
  33. "Ilikefootball",
  34. "IlikefootballandIlikebasketballtoo",
  35. "Ilikemovieandswim"
  36. };
  37. privateDate[]dates=null;
  38. privateint[]attachs={2,3,1,4,5,5};
  39. privateString[]names={"zhangsan","lisi","john","jetty","mike","jake"};
  40. privateDirectorydirectory=null;
  41. privateMap<String,Float>scores=newHashMap<String,Float>();
  42. privatestaticIndexReaderreader=null;
  43. publicIndexUtil(){
  44. try{
  45. setDates();
  46. scores.put("itat.org",2.0f);
  47. scores.put("zttc.edu",1.5f);
  48. //directory=FSDirectory.open(newFile("d:/lucene/index02"));
  49. directory=newRAMDirectory();
  50. index();
  51. reader=IndexReader.open(directory,false);
  52. }catch(IOExceptione){
  53. e.printStackTrace();
  54. }
  55. }
  56. /**
  57. *对于IndexReader而言,反复使用Index.open打开会有很大的开销,所以一般在整个程序的生命周期中
  58. *只会打开一个IndexReader,通过这个IndexReader来创建不同的IndexSearcher,如果使用单例模式,
  59. *可能出现的问题有:
  60. *1、当使用Writer修改了索引之后不会更新信息,所以需要使用IndexReader.openIfChange方法操作
  61. *如果IndexWriter在创建完成之后,没有关闭,需要进行commit操作之后才能提交
  62. *@return
  63. */
  64. publicIndexSearchergetSearcher(){
  65. try{
  66. if(reader==null){
  67. reader=IndexReader.open(directory,false);
  68. }else{
  69. IndexReadertr=IndexReader.openIfChanged(reader);
  70. //如果原来的reader没改变,返回null
  71. //如果原来的reader改变,则更新为新的索引
  72. if(tr!=null){
  73. reader.close();
  74. reader=tr;
  75. }
  76. }
  77. returnnewIndexSearcher(reader);
  78. }catch(CorruptIndexExceptione){
  79. e.printStackTrace();
  80. }catch(IOExceptione){
  81. e.printStackTrace();
  82. }
  83. returnnull;
  84. }
  85. privatevoidsetDates(){
  86. SimpleDateFormatsdf=newSimpleDateFormat("yyyy-MM-dd");
  87. try{
  88. dates=newDate[ids.length];
  89. dates[0]=sdf.parse("2010-02-19");
  90. dates[1]=sdf.parse("2012-01-11");
  91. dates[2]=sdf.parse("2011-09-19");
  92. dates[3]=sdf.parse("2010-12-22");
  93. dates[4]=sdf.parse("2012-01-01");
  94. dates[5]=sdf.parse("2011-05-19");
  95. }catch(ParseExceptione){
  96. e.printStackTrace();
  97. }
  98. }
  99. /**
  100. *把之前删除的索引数据进行恢复
  101. */
  102. publicvoidundelete(){
  103. //使用IndexReader进行恢复
  104. try{
  105. IndexReaderreader=IndexReader.open(directory,false);
  106. //恢复时,必须把IndexReader的只读(readOnly)设置为false
  107. reader.undeleteAll();
  108. reader.close();
  109. }catch(CorruptIndexExceptione){
  110. e.printStackTrace();
  111. }catch(StaleReaderExceptione){
  112. e.printStackTrace();
  113. }catch(LockObtainFailedExceptione){
  114. e.printStackTrace();
  115. }catch(IOExceptione){
  116. e.printStackTrace();
  117. }
  118. }
  119. /**
  120. *forceMerge是lucene3.5之前替代optimize方法的,其实只是改了个名称,因为优化的使效率变低
  121. *因为一到优化它就会全部更新索引,这个所涉及到的负载是很大的
  122. *所以改了个名称,不推荐使用,在做优化的时候会把索引回收站中的数据文件全部删除
  123. *lucene会在你写索引的时候根据你的索引的段越来越多会自动帮忙优化的,force是强制优化
  124. */
  125. publicvoidmerge(){
  126. IndexWriterwriter=null;
  127. try{
  128. writer=newIndexWriter(directory,
  129. newIndexWriterConfig(Version.LUCENE_35,newStandardAnalyzer(Version.LUCENE_35)));
  130. //会将索引合并为2段,这两段中的被删除的数据会被清空
  131. //特别注意:此处Lucene在3.5之后不建议使用,因为会消耗大量的开销,
  132. //Lucene会根据情况自动处理的
  133. writer.forceMerge(2);
  134. }catch(CorruptIndexExceptione){
  135. e.printStackTrace();
  136. }catch(LockObtainFailedExceptione){
  137. e.printStackTrace();
  138. }catch(IOExceptione){
  139. e.printStackTrace();
  140. }finally{
  141. try{
  142. if(writer!=null)writer.close();
  143. }catch(CorruptIndexExceptione){
  144. e.printStackTrace();
  145. }catch(IOExceptione){
  146. e.printStackTrace();
  147. }
  148. }
  149. }
  150. /**
  151. *假如你想要强制删除回收站的信息可以调用writer.forceMergeDeletes()这个方法,
  152. *但是这个方法不推荐使用,比较消耗内存,lucene会自动根据容量的大小删除所删除的文件
  153. */
  154. publicvoidforceDelete(){
  155. IndexWriterwriter=null;
  156. try{
  157. writer=newIndexWriter(directory,
  158. newIndexWriterConfig(Version.LUCENE_35,newStandardAnalyzer(Version.LUCENE_35)));
  159. writer.forceMergeDeletes();
  160. }catch(CorruptIndexExceptione){
  161. e.printStackTrace();
  162. }catch(LockObtainFailedExceptione){
  163. e.printStackTrace();
  164. }catch(IOExceptione){
  165. e.printStackTrace();
  166. }finally{
  167. try{
  168. if(writer!=null)writer.close();
  169. }catch(CorruptIndexExceptione){
  170. e.printStackTrace();
  171. }catch(IOExceptione){
  172. e.printStackTrace();
  173. }
  174. }
  175. }
  176. /**
  177. *删除索引数据,默认不会完全删除,被放入索引回收站
  178. */
  179. publicvoiddelete(){
  180. IndexWriterwriter=null;
  181. try{
  182. writer=newIndexWriter(directory,
  183. newIndexWriterConfig(Version.LUCENE_35,newStandardAnalyzer(Version.LUCENE_35)));
  184. //参数是一个选项,可以是一个Query,也可以是一个term,term是一个精确查找的值
  185. //此时删除的文档并不会被完全删除,而是存储在一个回收站中的,可以恢复
  186. //执行完这个操作,索引文件夹下就会多出一个名叫_0_1.del的文件,也就是删除的文件在这个文件中记录了
  187. writer.deleteDocuments(newTerm("id","1"));
  188. writer.commit();
  189. }catch(CorruptIndexExceptione){
  190. e.printStackTrace();
  191. }catch(LockObtainFailedExceptione){
  192. e.printStackTrace();
  193. }catch(IOExceptione){
  194. e.printStackTrace();
  195. }finally{
  196. try{
  197. if(writer!=null)writer.close();
  198. }catch(CorruptIndexExceptione){
  199. e.printStackTrace();
  200. }catch(IOExceptione){
  201. e.printStackTrace();
  202. }
  203. }
  204. }
  205. /**
  206. *使用reader删除,其实里面也会调用writer删除,
  207. *优点是使用reader删除马上会更新索引信息
  208. *现在一般还是使用writer来删除,reader.getWriter这个方法被过时了
  209. */
  210. publicvoiddelete02(){
  211. try{
  212. reader.deleteDocuments(newTerm("id","1"));
  213. }catch(CorruptIndexExceptione){
  214. e.printStackTrace();
  215. }catch(LockObtainFailedExceptione){
  216. e.printStackTrace();
  217. }catch(IOExceptione){
  218. e.printStackTrace();
  219. }
  220. }
  221. /**
  222. *更新操作
  223. *Lucene并没有提供更新,这里的更新操作其实是如下两个操作的合集
  224. *先删除之后再添加
  225. */
  226. publicvoidupdate(){
  227. IndexWriterwriter=null;
  228. try{
  229. writer=newIndexWriter(directory,
  230. newIndexWriterConfig(Version.LUCENE_35,newStandardAnalyzer(Version.LUCENE_35)));
  231. Documentdoc=newDocument();
  232. doc.add(newField("id","11",Field.Store.YES,Field.Index.NOT_ANALYZED_NO_NORMS));
  233. doc.add(newField("email",emails[0],Field.Store.YES,Field.Index.NOT_ANALYZED));
  234. doc.add(newField("content",contents[0],Field.Store.NO,Field.Index.ANALYZED));
  235. doc.add(newField("name",names[0],Field.Store.YES,Field.Index.NOT_ANALYZED_NO_NORMS));
  236. writer.updateDocument(newTerm("id","1"),doc);
  237. }catch(CorruptIndexExceptione){
  238. e.printStackTrace();
  239. }catch(LockObtainFailedExceptione){
  240. e.printStackTrace();
  241. }catch(IOExceptione){
  242. e.printStackTrace();
  243. }finally{
  244. try{
  245. if(writer!=null)writer.close();
  246. }catch(CorruptIndexExceptione){
  247. e.printStackTrace();
  248. }catch(IOExceptione){
  249. e.printStackTrace();
  250. }
  251. }
  252. }
  253. publicvoidquery(){
  254. try{
  255. IndexReaderreader=IndexReader.open(directory);
  256. //通过reader可以有效的获取到文档的数量
  257. System.out.println("numDocs:"+reader.numDocs());//存储的文档数//不包括被删除的
  258. System.out.println("maxDocs:"+reader.maxDoc());//总存储量,包括在回收站中的索引
  259. System.out.println("deleteDocs:"+reader.numDeletedDocs());
  260. reader.close();
  261. }catch(CorruptIndexExceptione){
  262. e.printStackTrace();
  263. }catch(IOExceptione){
  264. e.printStackTrace();
  265. }
  266. }
  267. /**
  268. *索引文件后缀为.fmn为保存的是域的名称等
  269. *.fdt和.fdx保存的是Store.YES的信息,保存域里面存储的数据
  270. *.frq表示这里的域哪些出现多少次,哪些单词出现多少次,
  271. *.nrm存储一些评分信息
  272. *.prx存储一些偏移量等
  273. *.tii和.tis专门存储索引里面的所有内容信息
  274. */
  275. publicvoidindex(){
  276. IndexWriterwriter=null;
  277. try{
  278. //在2.9版本之后,lucene的就不是全部的索引格式都兼容的了,所以在使用的时候必须写明版本号
  279. writer=newIndexWriter(directory,newIndexWriterConfig(Version.LUCENE_35,newStandardAnalyzer(Version.LUCENE_35)));
  280. writer.deleteAll();//清空索引
  281. Documentdoc=null;
  282. for(inti=0;i<ids.length;i++){
  283. doc=newDocument();
  284. doc.add(newField("id",ids[i],Field.Store.YES,Field.Index.NOT_ANALYZED_NO_NORMS));
  285. doc.add(newField("email",emails[i],Field.Store.YES,Field.Index.NOT_ANALYZED));
  286. doc.add(newField("email","test"+i+"@test.com",Field.Store.YES,Field.Index.NOT_ANALYZED));
  287. doc.add(newField("content",contents[i],Field.Store.NO,Field.Index.ANALYZED));
  288. doc.add(newField("name",names[i],Field.Store.YES,Field.Index.NOT_ANALYZED_NO_NORMS));
  289. //存储数字
  290. //NumberTools.stringToLong("");已经被标记为过时了
  291. doc.add(newNumericField("attach",Field.Store.YES,true).setIntValue(attachs[i]));
  292. //存储日期
  293. doc.add(newNumericField("date",Field.Store.YES,true).setLongValue(dates[i].getTime()));
  294. Stringet=emails[i].substring(emails[i].lastIndexOf("@")+1);
  295. System.out.println(et);
  296. if(scores.containsKey(et)){
  297. doc.setBoost(scores.get(et));
  298. }else{
  299. doc.setBoost(0.5f);//默认是1.0f
  300. }
  301. writer.addDocument(doc);
  302. }
  303. }catch(CorruptIndexExceptione){
  304. e.printStackTrace();
  305. }catch(LockObtainFailedExceptione){
  306. e.printStackTrace();
  307. }catch(IOExceptione){
  308. e.printStackTrace();
  309. }finally{
  310. try{
  311. if(writer!=null)writer.close();
  312. }catch(CorruptIndexExceptione){
  313. e.printStackTrace();
  314. }catch(IOExceptione){
  315. e.printStackTrace();
  316. }
  317. }
  318. }
  319. publicvoidsearch01(){
  320. try{
  321. IndexReaderreader=IndexReader.open(directory);
  322. IndexSearchersearcher=newIndexSearcher(reader);
  323. TermQueryquery=newTermQuery(newTerm("email","test0@test.com"));
  324. TopDocstds=searcher.search(query,10);
  325. for(ScoreDocsd:tds.scoreDocs){
  326. Documentdoc=searcher.doc(sd.doc);
  327. System.out.println("("+sd.doc+"-"+doc.getBoost()+"-"+sd.score+")"+
  328. doc.get("name")+"["+doc.get("email")+"]-->"+doc.get("id")+","+
  329. doc.get("attach")+","+doc.get("date")+","+doc.getValues("email")[1]);
  330. }
  331. reader.close();
  332. }catch(CorruptIndexExceptione){
  333. e.printStackTrace();
  334. }catch(IOExceptione){
  335. e.printStackTrace();
  336. }
  337. }
  338. publicvoidsearch02(){
  339. try{
  340. IndexSearchersearcher=getSearcher();
  341. TermQueryquery=newTermQuery(newTerm("content","like"));
  342. TopDocstds=searcher.search(query,10);
  343. for(ScoreDocsd:tds.scoreDocs){
  344. Documentdoc=searcher.doc(sd.doc);
  345. System.out.println(doc.get("id")+"---->"+
  346. doc.get("name")+"["+doc.get("email")+"]-->"+doc.get("id")+","+
  347. doc.get("attach")+","+doc.get("date")+","+doc.getValues("email")[1]);
  348. }
  349. searcher.close();
  350. }catch(CorruptIndexExceptione){
  351. e.printStackTrace();
  352. }catch(IOExceptione){
  353. e.printStackTrace();
  354. }
  355. }
  356. }
4、lucene的单元测试类
  1. packageorg.itat.test;
  2. importorg.itat.index.IndexUtil;
  3. importorg.junit.Test;
  4. publicclassTestIndex{
  5. @Test
  6. publicvoidtestIndex(){
  7. IndexUtiliu=newIndexUtil();
  8. iu.index();
  9. }
  10. @Test
  11. publicvoidtestQuery(){
  12. IndexUtiliu=newIndexUtil();
  13. iu.query();
  14. }
  15. @Test
  16. publicvoidtestDelete(){
  17. IndexUtiliu=newIndexUtil();
  18. iu.delete();
  19. }
  20. @Test
  21. publicvoidtestDelete02(){
  22. IndexUtiliu=newIndexUtil();
  23. iu.delete02();
  24. }
  25. @Test
  26. publicvoidtestUnDelete(){
  27. IndexUtiliu=newIndexUtil();
  28. iu.undelete();
  29. }
  30. @Test
  31. publicvoidtestForceDelete(){
  32. IndexUtiliu=newIndexUtil();
  33. iu.forceDelete();
  34. }
  35. @Test
  36. publicvoidtestMerge(){
  37. IndexUtiliu=newIndexUtil();
  38. iu.merge();
  39. }
  40. @Test
  41. publicvoidtestUpdate(){
  42. IndexUtiliu=newIndexUtil();
  43. iu.update();
  44. }
  45. @Test
  46. publicvoidtestSearch01(){
  47. IndexUtiliu=newIndexUtil();
  48. iu.search01();
  49. }
  50. @Test
  51. publicvoidtestSearch02(){
  52. IndexUtiliu=newIndexUtil();
  53. for(inti=0;i<5;i++){
  54. iu.search02();
  55. System.out.println("-----------------------------");
  56. try{
  57. Thread.sleep(10000);
  58. }catch(InterruptedExceptione){
  59. e.printStackTrace();
  60. }
  61. }
  62. }
  63. }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值