lucene(索引的建立)

    xiaoxiao2021-04-11  37

    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段 强制合并已删除的文档(清空回收站)这样就不能恢复了 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、对数字进行索引可以使用分词器进行不同的索引

      ·WhitespaceAnalyzerStandardAnalyzer会索引数字

      ·SimpleAnalyzerStopAnalyzer不会索引数字

    2、在3.0之后添加了数字域来完成数字和日期的索引

    转载请注明原文地址: https://ju.6miu.com/read-666605.html

    最新回复(0)