lucene索引

[亡魂溺海] 提交于 2020-03-15 08:19:27

一、lucene索引

1、文档层次结构

  • 索引(Index):一个索引放在一个文件夹中;
  • 段(Segment):一个索引中可以有很多段,段与段之间是独立的,添加新的文档可能产生新段,不同的段可以合并成一个新段;
  • 文档(Document):文档是创建索引的基本单位,不同的文档保存在不同的段中,一个段可以包含多个文档;
  • 域(Field):一个文档包含不同类型的信息,可以拆分开索引;
  • 词(Term):词是索引的最小单位,是经过词法分析和语言处理后的数据;

  文档是Lucene索引和搜索的原子单位,文档为包含一个或多个域的容器,而域则依次包含“真正的”被搜索内容,域值通过分词技术处理,得到多个词元。如一篇小说信息可以称为一个文档;小说信息又包含多个域,比如标题,作者、简介、最后更新时间等;对标题这一个域采用分词技术,又可以等到一个或多个词元。

2、正向索引与反向索引

  • 正向索引:文档占据了中心的位置,每个文档指向了一个它所包含的索引项的序列。正向信息就是按层次保存了索引一直到词的包含关系: 索引 -> 段-> 文档 -> 域 -> 词
  • 反向索引:一种以索引项为中心来组织文档的方式,每个索引项指向一个文档序列,这个序列中的文档都包含该索引项。反向信息保存了词典的倒排表映射:词 -> 文档

  lucene使用到的就是反向索引。如下图所示:

二、索引操作

  相关示例如下:

  1 package com.test.lucene;
  2 
  3 import java.io.IOException;
  4 import java.nio.file.Paths;
  5 
  6 import org.apache.lucene.analysis.Analyzer;
  7 import org.apache.lucene.analysis.cn.smart.SmartChineseAnalyzer;
  8 import org.apache.lucene.document.Document;
  9 import org.apache.lucene.document.Field.Store;
 10 import org.apache.lucene.document.IntField;
 11 import org.apache.lucene.document.StringField;
 12 import org.apache.lucene.document.TextField;
 13 import org.apache.lucene.index.DirectoryReader;
 14 import org.apache.lucene.index.IndexWriter;
 15 import org.apache.lucene.index.IndexWriterConfig;
 16 import org.apache.lucene.index.Term;
 17 import org.apache.lucene.index.IndexWriterConfig.OpenMode;
 18 import org.apache.lucene.queryparser.classic.ParseException;
 19 import org.apache.lucene.queryparser.classic.QueryParser;
 20 import org.apache.lucene.search.IndexSearcher;
 21 import org.apache.lucene.search.Query;
 22 import org.apache.lucene.search.TopDocs;
 23 import org.apache.lucene.store.Directory;
 24 import org.apache.lucene.store.FSDirectory;
 25 
 26 /**
 27  * 索引增删改查
 28  */
 29 public class IndexTest {
 30     /**
 31      * 创建索引
 32      * 
 33      * @param path
 34      *            索引存放路径
 35      */
 36     public static void create(String path) {
 37         System.out.println("创建开始=============================》");
 38         Analyzer analyzer = new SmartChineseAnalyzer();// 指定分词技术,这里使用的是中文分词
 39 
 40         IndexWriterConfig indexWriterConfig = new IndexWriterConfig(analyzer);// indexWriter的配置信息
 41 
 42         indexWriterConfig.setOpenMode(OpenMode.CREATE_OR_APPEND); // 索引的打开方式:没有则创建,有则打开
 43 
 44         Directory directory = null;
 45         IndexWriter indexWriter = null;
 46         // 文档一
 47         Document doc1 = new Document();
 48         doc1.add(new StringField("id", "1111", Store.YES));
 49         doc1.add(new TextField("content", "中国广州", Store.YES));
 50         doc1.add(new IntField("num", 1, Store.YES));
 51 
 52         // 文档二
 53         Document doc2 = new Document();
 54         doc2.add(new StringField("id", "2222", Store.YES));
 55         doc2.add(new TextField("content", "中国上海", Store.YES));
 56         doc2.add(new IntField("num", 2, Store.YES));
 57 
 58         try {
 59             directory = FSDirectory.open(Paths.get(path));// 索引在硬盘上的存储路径
 60             indexWriter = new IndexWriter(directory, indexWriterConfig);
 61             indexWriter.addDocument(doc1);
 62             indexWriter.addDocument(doc2);
 63             // 将indexWrite操作提交,如果不提交,之前的操作将不会保存到硬盘
 64             // 但是这一步很消耗系统资源,索引执行该操作需要有一定的策略
 65             indexWriter.commit();
 66         } catch (IOException e) {
 67             e.printStackTrace();
 68         } finally { // 关闭资源
 69             try {
 70                 indexWriter.close();
 71                 directory.close();
 72             } catch (IOException e) {
 73                 e.printStackTrace();
 74             }
 75         }
 76         System.out.println("创建索引完成=================================");
 77     }
 78 
 79     /**
 80      * 添加索引
 81      * 
 82      * @param path
 83      *            索引存放路径
 84      * @param document
 85      *            添加的文档
 86      */
 87     public static void add(String path, Document document) {
 88         System.out.println("增加索引开始=============================》");
 89         Analyzer analyzer = new SmartChineseAnalyzer();// 指定分词技术,这里使用的是中文分词
 90 
 91         IndexWriterConfig indexWriterConfig = new IndexWriterConfig(analyzer);// indexWriter的配置信息
 92 
 93         indexWriterConfig.setOpenMode(OpenMode.CREATE_OR_APPEND); // 索引的打开方式:没有则创建,有则打开
 94         Directory directory = null;
 95         IndexWriter indexWriter = null;
 96         try {
 97             directory = FSDirectory.open(Paths.get(path));// 索引在硬盘上的存储路径
 98 
 99             indexWriter = new IndexWriter(directory, indexWriterConfig);
100             indexWriter.addDocument(document);
101             indexWriter.commit();
102         } catch (IOException e) {
103             e.printStackTrace();
104         } finally { // 关闭资源
105             try {
106                 indexWriter.close();
107                 directory.close();
108             } catch (IOException e) {
109                 e.printStackTrace();
110             }
111         }
112         System.out.println("增加索引完成=================================");
113     }
114 
115     /**
116      * 删除索引
117      * 
118      * @param indexpath
119      *            索引存放路径
120      * @param id
121      *            文档id
122      */
123     public static void delete(String indexpath, String id) {
124         System.out.println("删除索引开始=============================》");
125         Analyzer analyzer = new SmartChineseAnalyzer();// 指定分词技术,这里使用的是中文分词
126 
127         IndexWriterConfig indexWriterConfig = new IndexWriterConfig(analyzer);// indexWriter的配置信息
128 
129         indexWriterConfig.setOpenMode(OpenMode.CREATE_OR_APPEND); // 索引的打开方式:没有则创建,有则打开
130         IndexWriter indexWriter = null;
131         Directory directory = null;
132         try {
133             directory = FSDirectory.open(Paths.get(indexpath));// 索引在硬盘上的存储路径
134             indexWriter = new IndexWriter(directory, indexWriterConfig);
135             indexWriter.deleteDocuments(new Term("id", id));// 删除索引操作
136         } catch (IOException e) {
137             e.printStackTrace();
138         } finally { // 关闭资源
139             try {
140                 indexWriter.close();
141                 directory.close();
142             } catch (IOException e) {
143                 e.printStackTrace();
144             }
145         }
146         System.out.println("删除索引完成=================================");
147     }
148 
149     /**
150      * Lucene没有真正的更新操作,通过某个fieldname,可以更新这个域对应的索引,但是实质上,它是先删除索引,再重新建立的。
151      * 
152      * @param indexpath
153      *            索引存放路径
154      * @param newDoc
155      *            更新后的文档
156      * @param oldDoc
157      *            需要更新的目标文档
158      */
159     public static void update(String indexpath, Document newDoc, Document oldDoc) {
160         System.out.println("更新索引开始=============================》");
161         Analyzer analyzer = new SmartChineseAnalyzer();
162         IndexWriterConfig config = new IndexWriterConfig(analyzer);
163         config.setOpenMode(OpenMode.CREATE_OR_APPEND);
164         IndexWriter indexWriter = null;
165         Directory directory = null;
166         try {
167             directory = FSDirectory.open(Paths.get(indexpath));
168             indexWriter = new IndexWriter(directory, config);
169             indexWriter.updateDocument(new Term("id", oldDoc.get("id")), newDoc);
170         } catch (IOException e) {
171             e.printStackTrace();
172         } finally { // 关闭资源
173             try {
174                 indexWriter.close();
175                 directory.close();
176             } catch (IOException e) {
177                 e.printStackTrace();
178             }
179         }
180         System.out.println("更新索引完成=================================");
181     }
182 
183     /**
184      * 搜索
185      * 
186      * @param keyword
187      *            关键字
188      * @param indexpath
189      *            索引存放路径
190      */
191     public static void search(String keyword, String indexpath) {
192         Directory directory = null;
193         try {
194             directory = FSDirectory.open(Paths.get(indexpath));// 索引硬盘存储路径
195 
196             DirectoryReader directoryReader = DirectoryReader.open(directory);// 读取索引
197 
198             IndexSearcher searcher = new IndexSearcher(directoryReader);// 创建索引检索对象
199 
200             Analyzer analyzer = new SmartChineseAnalyzer();// 分词技术
201 
202             QueryParser parser = new QueryParser("content", analyzer);// 创建Query
203             Query query = parser.parse(keyword);// 查询content为广州的
204             // 检索索引,获取符合条件的前10条记录
205             TopDocs topDocs = searcher.search(query, 10);
206             if (topDocs != null) {
207                 System.out.println("符合条件的记录为: " + topDocs.totalHits);
208                 for (int i = 0; i < topDocs.scoreDocs.length; i++) {
209                     Document doc = searcher.doc(topDocs.scoreDocs[i].doc);
210                     System.out.println("id = " + doc.get("id"));
211                     System.out.println("content = " + doc.get("content"));
212                     System.out.println("num = " + doc.get("num"));
213                 }
214             }
215             directory.close();
216             directoryReader.close();
217         } catch (IOException e) {
218             e.printStackTrace();
219         } catch (ParseException e) {
220             e.printStackTrace();
221         }
222     }
223     /**
224      * 测试代码
225      * @param args
226      */
227     public static void main(String[] args) {
228         String indexpath = "D://index/test";
229         create(indexpath);// 创建索引
230         search("广州", indexpath);
231         Document doc = new Document();
232         doc.add(new StringField("id", "3333", Store.YES));
233         doc.add(new TextField("content", "中国北京广州", Store.YES));
234         doc.add(new IntField("num", 2, Store.YES));
235         add(indexpath, doc);// 添加索引
236         search("广州", indexpath);
237         Document newDoc = new Document();
238         newDoc.add(new StringField("id", "3333", Store.YES));
239         newDoc.add(new TextField("content", "中国北京广州我的顶顶顶顶顶顶顶顶顶顶顶顶", Store.YES));
240         newDoc.add(new IntField("num", 3, Store.YES));
241         update(indexpath, newDoc, doc);// 更新索引
242         search("广州", indexpath);
243         delete(indexpath, "3333");// 删除索引
244         search("广州", indexpath);
245     }
246 }

  运行结果如下:

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!