基本上创建索引需要三个步骤:

1、创建索引库IndexWriter对象

2、根据文件创建文档Document

3、向索引库中写入文档内容

这其中主要涉及到了IndexWriter(索引的核心组件,用于创建或追加索引)、Document(代表一些域Field的集合)、Field(具体的域,如文档创建时间、作者、内容等)、Analyzer(分词器)、Directory(用于描述索引存放位置)这些主要的类。

我们参照上一节的代码来看建立索引。

1、创建IndexWriter

// 索引文件的保存位置
Directory dir = FSDirectory.open(new File(indexStorePath));
// 分析器
Analyzer analyzer = new StandardAnalyzer(Version.LUCENE_4_9);
// 配置类
IndexWriterConfig iwc = new IndexWriterConfig(Version.LUCENE_4_9, analyzer);
iwc.setOpenMode(OpenMode.CREATE);// 创建模式 OpenMode.CREATE_OR_APPEND 添加模式
IndexWriter writer = new IndexWriter(dir, iwc);

这里先是定义存放索引文件的位置,然后定义分析器(分词器),我这里没有使用昨天提到的一个官方的smartcn那个jar的分词器,自己试了一下,发现不是很好用,居然是搜索失败的。不过中文的话,应该还是IK Analyzer比较好吧。

StandardAnalyzer是 lucene 中内置的“标准分析器”,可以做如下功能:

l  对原有句子按照空格进行了分词

l  所有的大写字母都可以能转换为小写的字母

l  可以去掉一些没有用处的单词,例如”is”,”the”,”are”等单词,也删除了所有的标点

当然这里也可以一些其他的分词器,Lucene中也自带了中文的分词器,是lucene-analyzers-smartcn.Jar中的SmartChineseAnalyzer,但是我用了一下发现对中文的处理并不好。

当然其他的中文分词器还有很流行的IKAnalyzer,这个一定要用FF的版本,意思是for four才是给我们4.x用的。

在下面是定义配置类,这里有个setOpenMode,有下面几个选项:

APPEND:总是追加,可能会导致错误,索引还会重复,导致返回多次结果

CREATE:清空重建(推荐)

CREATE_OR_APPEND【默认】:创建或追加

这里还是建议先用CREATE吧,当然学习的深入了之后使用CREATE_OR_APPEND可能会让索引创建效率更高。

另外,IndexWriter的创建也是相当耗费资源的,所以如有可能,尽量使用单例(注意线程 安全 )。

2、根据数据创建文档

首先说下Field、Document、索引之间的关系,简单一句话:多个Field组成一个Document,多个Document组成一个索引。

在创建索引的过程中比较重要的就是创建不同的Field,看看api就可以知道Field有哪些实现:BinaryDocValuesField, DoubleField, FloatField, IntField, LongField, NumericDocValuesField, SortedDocValuesField, SortedNumericDocValuesField, SortedSetDocValuesField, StoredField, StringField, TextField。

比较常用的有LongField、StoredField、StringField、TextField。具体有哪些构造方法建议大家自己查阅api文档。

每种Field都有具体的介绍,我这里重点介绍一下常用的几个:

LongField:索引但是不分词,适用于全部搜索,一般用于文件创建、修改时间的秒数等。

StoredField:只存不索引

StringField:索引但是不分词,所以适用于全部搜索的内容,比如国家等,要么不对,要么就是全对。另外提一句,这个有个长度限制是32766,大家使用的时候自己斟酌一下,一般不会超过。

TextField:索引并分词,所以这个应该是我们做 全文检索 的时候应该最常用到的一个Field。

Document doc = new Document();
FileInputStream is = new FileInputStream(f);
Reader reader = new BufferedReader(new InputStreamReader(is));
// 字符串 StringField LongField TextField
Field pathField = new StringField("path", f.getAbsolutePath(), Field.Store.YES);
Field contenField = new TextField("contents", reader);
// 添加字段
doc.add(contenField);
doc.add(pathField);

这样首先声明一个Document,然后声明一系列Field,然后添加字段即可。

这里有个重点就是Field,其实也比较简单。在4.x以前是没有各种各样的Field的,都是通过传参,现在就已经有了不同的实现,可以按需选择了。

StringField即为NOT_ANALYZED的(即不对域的内容进行分割分析),而TextField是ANALYZED的,因此,创建Field对象时,无需再指定分析类型了。

下面是官方描述:

StringField: A field that is indexed but not tokenized

TextField: A field that is indexed and tokenized

下面介绍一些有关Field的相关选项

a. Field.Store.Yes/No

在创建Field的时候,需要传入一个参数,来指定内容是否需要存储到索引中。这些被存储的内容可以在搜索结果中返回,用于展现显示,即使用document.get(“name”)时,是否可以直接返回内容。

一般文件的作者、创建时间、文件名等信息可以存储,但是内容就没必要存储了,一方面是内容太多太大,另一方面也是因为我们的程序可以引导用户直接访问原文件查看即可。

b.加权(后面会细说)

可以对Filed及Document进行加权。注意加权是影响返回结果顺序的一个因素,但也仅仅是一个因素,它和其它因素一起构成了Lucene的排序 算法 。

下面继续介绍一个对富文本(非纯文本)索引的方法。

对于word,excel,pdf等富文本,FileReader读取到的会是 乱码 ,无法有效的索引。这时候可以使用Tika等工具先将其正文内容提取出来,然后再进行索引。

使用Tika进行正文提取的方法见我的github:

https://github.com/irfen/lucene-example/blob/master/src/main/java/me/irfen/lucene/ch03/TikaBasicUtil.java

https://github.com/irfen/lucene-example/blob/master/src/test/java/me/irfen/lucene/ch03/TikaTest.java

更多Tika内容以后如果有时间会详细介绍。这里我使用的是Tika1.5版本,他依赖的包有点多,使用maven进行构建只需要如下两个配置即可:

<dependency>
<groupId>org.apache.tika</groupId>
<artifactId>tika-core</artifactId>
<version>1.5</version>
</dependency>
<dependency>
<groupId>org.apache.tika</groupId>
<artifactId>tika-parsers</artifactId>
<version>1.5</version>
</dependency>

3、向索引库中写入文档内容

这一步很简单,直接就是writer.addDocument(doc);就可以了。

这里简单介绍下对索引的优化,索引过程中,会将索引结果放到多个索引文件中,这样会回收索引的效率,但在搜索时,需要将多个索引文件中的返回结果并进行合并处理,因此效率较低。

在添加文档之后执行writer.forceMerge(2);,索引的优化是将索引结果文件归为一个或者有限的多个,它加大索引过程中的耗时(降低了效率),减少了搜索时的耗时(提高了效率)。

4、关于Directory

目前用的比较多的有两个Directory,一个是FSDirectory,一个是RAMDirectory。

看一眼FSDirectory的源码,会发现下面这段:

public static FSDirectory open(File path, LockFactory lockFactory) throws IOException {
if (Constants.JRE_IS_64BIT && MMapDirectory.UNMAP_SUPPORTED) {
return new MMapDirectory(path, lockFactory);
} else if (Constants.WINDOWS) {
return new SimpleFSDirectory(path, lockFactory);
} else {
return new NIOFSDirectory(path, lockFactory);
}
}

其实FSDirectory是根据不同的操作系统和JRE返回不同的Directory。

而另一个常用的是RAMDirectory,这个是内存索引,只对小索引好用,大量索引会导致频繁GC。

另外介绍一下FileSwitchDirectory,这是一个基于文件目录切换的一个实现。有时候我们想要同时获得两个Directory的优点,这就是FileSwitchDirectory的作用。下面是他的构造方法:

public FileSwitchDirectory(Set primaryExtensions, Directory primaryDir, Directory secondaryDir, boolean doClose) {
this.primaryExtensions = primaryExtensions;
this.primaryDir = primaryDir;
this.secondaryDir = secondaryDir;
this.doClose = doClose;
this.lockFactory = primaryDir.getLockFactory();
}

这里可以看到他要两个Directory,通过第一个参数我们可以指定主索引需要加载的索引文件,其它的将会由从Directory来实现,由此达到快速切换不同的Directory来使用他们各自的优点。

Lucene4.9学习笔记——Lucene建立索引的更多相关文章

  1. SQL反模式学习笔记4 建立主键规范【需要ID】

    目标:建立主键规范 反模式:每个数据库中的表都需要一个伪主键Id 在表中,需要引入一个对于表的域模型无意义的新列来存储一个伪值,这一列被用作这张表的主键, 从而通过它来确定表中的一条记录,即便其他的列 ...

  2. SQL反模式学习笔记13 使用索引

    目标:优化性能 改善性能最好的技术就是在数据库中合理地使用索引.  索引也是数据结构,它能使数据库将指定列中的某个值快速定位在相应的行. 反模式:无规划的使用索引 1.不使用索引或索引不足 2.使用了 ...

  3. Mysql数据库学习笔记之数据库索引(index)

    什么是索引: SQL索引有两种,聚集索引和非聚集索引,索引主要目的是提高了SQL Server系统的性能,加快数据的查询速度与减少系统的响应时间. 聚集索引:该索引中键值的逻辑顺序决定了表中相应行的物 ...

  4. Lucene建立索引搜索入门实例

                                第一部分:Lucene建立索引 Lucene建立索引主要有以下两步:第一步:建立索引器第二步:添加索引文件准备在f盘建立lucene文件夹,然后 ...

  5. 【转】Lucene不同版本中Field的Keyword、UnIndex,导致lucene 建立索引总是报错 急!!

    lucene 建立索引 总是报错 急!! http://zhidao.baidu.com/link?url=iaVs9JH4DfN6iwaWImt7VMJENWCWGGaWFGPjqhUw_jz7Fs ...

  6. python学习笔记:建立一个自己的搜索引擎

    写学习笔记是我学习python以来养成的一个习惯,每学习一个知识点,便整理成文字记录下来.搜索引擎大家经常都有在使用,国内外也很很多搜索引擎平台. Google搜索引擎建立至今已经快20年了,之后全球 ...

  7. lucene 建立索引的过程

    时间 -- ::  CSDN博客 原文 http://blog.csdn.net/caohaicheng/article/details/ 看lucene主页(http://lucene.apach ...

  8. 用Lucene4.5对中文文本建立索引

    这里需要完成一个能对txt文本建立索引,并能完成检索查询.完成这个功能,使用的是Lucene4.5,同时使用其自带的中文分析器. 准备工作是在一个文件夹里面建一些txt文件,这是我的文件结构: 首先要 ...

  9. lucene建立索引的过程

    建立索引过程 用户提交数据=>solr建立索引=>调用lucene包建立索引 官方建立索引和查询索引的例子如下: http://lucene.apache.org/core/4_10_3/ ...

随机推荐

  1. IOS Label 自动换行 IOS6和IOS7

    IOS 6和ios7 不一样,所以,我们分开来: IOS6: //计算实际frame大小,并将label的frame变成实际大小     CGSize size01 = [ssizeWithFont: ...

  2. hdu 3183 A Magic Lamp(RMQ)

    题目链接:hdu 3183 A Magic Lamp 题目大意:给定一个字符串,然后最多删除K个.使得剩下的组成的数值最小. 解题思路:问题等价与取N-M个数.每次取的时候保证后面能取的个数足够,而且 ...

  3. Android多线程研究(4)——从一道面试题说起

    有一道这种面试题:开启一个子线程和主线程同一时候运行,子线程输出10次后接着主线程输出100次,如此重复50次.先看以下代码: package com.maso.test; /** * * @auth ...

  4. tomcat安全配置之证书密码加密存储

    最近项目组要完成一个新Web Servicer接口的开发,其中有项要求是支持外部客户程序以https方式访问这些SOAP接口.项目组当前基于tomcat6.0.29开发,axis版本为1.4.拿到这个 ...

  5. 在TextView使用部分颜色文字

    /** * change a part of string color. * * @param string * whole string. * @param subString * the sub ...

  6. contentProvider模板

    package com.example.qunzheng.todolist.provider; import android.content.ContentProvider; import andro ...

  7. SpringMVC关于json、xml自动转换的原理研究[附带源码分析 --转

    SpringMVC关于json.xml自动转换的原理研究[附带源码分析] 原文地址:http://www.cnblogs.com/fangjian0423/p/springMVC-xml-json-c ...

  8. struts2+ajax

    web网页开发中需要用到struts2来处理action,通过struts2定义后端java类. <action name="loginAction" class=" ...

  9. Web Services之SOAP学习

    Web Services之SOAP [toc] 什么是SOAP SOAP(Simple Object Access Protocol)简单对象访问协议是在分散或分布式的环境中交换信息的简单的协议,是一 ...

  10. Punycode与中文互转

    Punycode是一个根据RFC 3492标准而制定的编码系统,主要用于把域名从地方语言所采用的Unicode编码转换成为可用于DNS系统的编码 "中文域名"不被标准的解析服务器支 ...