您的位置:首页 > 其它

lucene(索引的建立)

2017-04-15 00:48 381 查看

lucene的使用(索引的创建)

索引过程的核心类:IndexWriter,Directory,Analyzer,Document,Field

准备的jar包:

<dependency>
<groupId>org.apache.lucene</groupId>
<artifactId>lucene-core</artifactId>
<version>3.5.0</version>
</dependency>


首先提供简单的索引创建实例,代码如下:

Directory directory = FSDirectory.open(new File("索引文件存放的位置"));
IndexWriter writer = new IndexWriter(directory, new IndexWriterConfig(Version.LUCENE_35, new StandardAnalyzer(Version.LUCENE_35)));
File file = new File("d:/lucene/example");// 此处作者使用的是本地的文件作为数据
Document doc = null;
Random ran = new Random();
int index = 0;
for (File f : file.listFiles()) {
int score = ran.nextInt(600);
doc = new Document();
doc.add(new Field("id", String.valueOf(index++), Field.Store.YES,Field.Index.NOT_ANALYZED_NO_NORMS));
doc.add(new Field("content", new FileReader(f)));
doc.add(new Field("filename", f.getName(), Field.Store.YES,Field.Index.NOT_ANALYZED));
doc.add(new Field("path", f.getAbsolutePath(), Field.Store.YES,Field.Index.NOT_ANALYZED));
doc.add(new NumericField("date", Field.Store.YES, true).setLongValue(f.lastModified()));
doc.add(new NumericField("size", Field.Store.YES, true).setIntValue((int) (f.length())));
doc.add(new NumericField("score", Field.Store.NO, true).setIntValue(score));
writer.addDocument(doc);
}
writer.close();


索引的删除
// 如果重新创建,则删除之前的内容
writer.deleteAll();
writer.deleteDocuments(new Term("id","1"));

索引的恢复

// 使用IndexReader进行恢复
IndexReader reader = IndexReader.open(directory, false);
// 恢复时,必须把IndexReader的只读?readOnly)设置为false
reader.undeleteAll();
reader.close();
合并段信息



writer.forceMerge(1);//合并为1段
[b]强制合并已删除的文档(清空回收站)这样就不能恢复了

[/b]
writer.forceMergeDeletes();


索引的更新


Document doc = new Document();
doc.add(new Field("id", "11", Field.Store.YES,
Field.Index.NOT_ANALYZED_NO_NORMS));
doc.add(new Field("email", "test" + emails[0] + "@test.com",
Field.Store.YES, Field.Index.NOT_ANALYZED));
doc.add(new Field("content", contents[0], Field.Store.NO,
Field.Index.ANALYZED));
doc.add(new Field("name", names[0], Field.Store.YES,
Field.Index.NOT_ANALYZED_NO_NORMS));
// 存储数字
doc.add(new NumericField("attach", Field.Store.YES, true)
.setIntValue(attachs[0]));
// 存储日期
doc.add(new NumericField("date", Field.Store.YES, true)
.setLongValue(dates[0].getTime()));
writer.updateDocument(new Term("id", "1"), doc);


索引创建的过程分析图



索引建立的简单步骤

创建Directory

Directory directory = FSDirectory.open(new File("索引文件存放的位置"));


注:此处使用的是FSDirectory是存放在磁盘上的,还有一种是RAMDirectory是存放在内存中的,但是没有办法持久化,所以推荐使用FSDirectory

创建IndexWriter

IndexWriter writer = new IndexWriter(directory, new IndexWriterConfig(
Version.LUCENE_35, new StandardAnalyzer(Version.LUCENE_35)));//StandardAnalyzer标准分词器

分词(分词器核心)

Analyzer

SimpleAnalyzer(简单分词)、StopAnalyzer(停用词分词)、WhitespaceAnalyzer(空格符分词)、StandardAnalyzer(标准分词)

TokenStream

分词器做好处理之后得到的一个流,这个流中存储了分词的各种信息,可以通过TokenStream有效的获取到分词单元信息
生成的流程:



tokenStream里面存储的值(存储值代码核心)

Analyzer a = new StandardAnalyzer(Version.LUCENE_35);//此处使用的是标准分词
TokenStream stream = a.tokenStream("content", new StringReader(str));
// 位置增量的属性,存储语汇单元之间的距离
PositionIncrementAttribute pia = stream.addAttribute(PositionIncrementAttribute.class);
// 每个语汇单元的位置的偏移量
OffsetAttribute oa = stream.addAttribute(OffsetAttribute.class);
// 存储每一个语汇单元的信息(分词单元信息)
CharTermAttribute cta = stream.addAttribute(CharTermAttribute.class);
// 使用的分词器的类型信息
TypeAttribute ta = stream.addAttribute(TypeAttribute.class);
for (; stream.incrementToken();) {
System.out.print(pia.getPositionIncrement() + "=");
System.out.println(cta + "[" + oa.startOffset() + "-"+ oa.endOffset() + "-type-" + ta.type() + "\n");
}


在这个流中所需要存储的数据



Tokenizer

作用:主要负责接收字符流Reader,将Reader进行分词操作。有如下一些实现类



TokenFilter

(将分词的语汇单元,进行各种各样过滤)



补充:自定义分词(以stop分词举例)



说明:现在都是用的是中文分词,jar包是:

<dependency>
<groupId>com.janeluo</groupId>
<artifactId>ikanalyzer</artifactId>
<version>2012_u6</version>
</dependency>

//java中创建分词:
Analyzer anal=new IKAnalyzer(true);


创建文档并且添加索引

File file = new File("d:/lucene/example");//此处作者使用的是本地的文件作为数据
Document doc = null;
Random ran = new Random();
int index = 0;
for (File f : file.listFiles()) {
int score = ran.nextInt(600);
doc = new Document();
doc.add(new Field("id", String.valueOf(index++),Field.Store.YES, Field.Index.NOT_ANALYZED_NO_NORMS));
doc.add(new Field("content", new FileReader(f)));
doc.add(new Field("filename", f.getName(), Field.Store.YES,Field.Index.NOT_ANALYZED));
doc.add(new Field("path", f.getAbsolutePath(), Field.Store.YES,Field.Index.NOT_ANALYZED));
doc.add(new NumericField("date", Field.Store.YES, true).setLongValue(f.lastModified()));
doc.add(new NumericField("size", Field.Store.YES, true).setIntValue((int) (f.length())));
doc.add(new NumericField("score", Field.Store.NO, true).setIntValue(score));
writer.addDocument(doc);
}
writer.close();

索引域选项

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

存储域选项

Field.Store.*
YES:将会存储域值,原始字符串的值会保存在索引,以此可以进行相应的恢复操作,对于主键,标题可以是这种方式存储
NO:不会存储域值,通常与Index.ANAYLIZED合起来使用,索引一些如文章正文等不需要恢复的文档

最佳实践






补充:

1、对数字进行索引可以使用分词器进行不同的索引
·WhitespaceAnalyzer和StandardAnalyzer会索引数字
·SimpleAnalyzer和StopAnalyzer不会索引数字
2、在3.0之后添加了数字域来完成数字和日期的索引
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: