Lucene学习总结

在使用Lucene前,我们先大致熟悉下Lucene的几个核心类。

核心索引类:

  • public class IndexWriter

  索引过程的中心组件,把它想象成一个可以对索引进行写操作的对象。

  • public abstract class Directry

  Directory代表索引所在的位置,该抽象类有两个具体的子类实现。FSDirectory表示存储在文件系统的索引位置,RAMDirectory表示存储在内存中的索引位置。

  

  • public abstract class Analyzer

    分词组件。在建立索引前首先要对文档进行分词,Lucene默认有一些分词类的实现,自己实现的分词要继承该类。

  • public final class Document

    Document类似于数据库中的一条记录,它由好几个字段Field组成。

  • public final class Field

    Field用来描述文档的某个属性,例如文章的标题,内容等等。

核心搜索类:

  • public class IndexSeacher

    用来在已经建好的索引上进行搜索操作

  • public final class Term

    搜索的基本单元。Term对象有两个域组成。Term term = new Term("fieldName","queryWord");

  • public abstract class Query

    抽象类,有很多具体实现类。该类主要作用把用户输入的查询语句转换为Lucene能够是别的query。

  • public final class Hits(TopDocs)

    Hits是用来保存查询得到的结果的。最新版的Lucene中,TopDocs已代替了Hits。

   我们拿一张纸、一支笔,填写下面的表格:    


序号


文件名


文件路径


文件类型


文件大小


修改时间


内容


……

               

填完以后,搜索的时候就可以照着这张纸“按图索骥”了。

在lucene中,这张纸叫做Directory(也就是索引保存的目录),这支笔叫做IndexWriter,表格中一条记录叫做Document,记录中的每项叫做Field。

下面我们来看第一个简单的Lucene实现索引的例子(Lucene版本为4.10.1)。

public class LuceneDemo {

    public static void main(String[] args){

        //RAMDirectory(内存路径)继承自Directory抽象类,另一个继承自该类的是FSDirectory(文件系统路径),Directory dir = FSDirectory.open(new File("此处写索引存储的位置,"));
        Directory dir = new RAMDirectory();

        //SimpleAnalyzer继承自抽象类Analyzer,是分词组件,不同语言有不同的分词组件包,也可以自己定义实现该抽象类
        Analyzer analyzer = new SimpleAnalyzer();

        //定义IndexWriterConfig
        IndexWriterConfig iwc = new IndexWriterConfig(Version.LATEST, analyzer);

        //定义document对象
        Document doc = new Document();

        try {

            //第一步,切词入库,创建索引。定义IndexWriter对索引进行“写”操作
            IndexWriter iw = new IndexWriter(dir, iwc);

            //Field对象的构造方法有四个参数,前两个参数表示要建立索引的name和value,name指索引的名称,value指要建立索引的“文档对象”,例如博客的标题、正文
            //Field.Store有YES和NO两个值,表示是否存储该Field
            //Field.Index有5个不同的取值,ANALYZED,ANALYZED_NO_NORMS,NOT_ANALYZED,NOT_ANALYZED_NO_NORMS,NO,根据不同情况选择是否分词
            doc.add(new Field("title", "james bonde", Field.Store.YES, Field.Index.ANALYZED));
            doc.add(new Field("content","He want to go to school next year.",Field.Store.YES,Field.Index.ANALYZED));
            doc.add(new Field("doc","He will go to his mother‘s home.",Field.Store.YES,Field.Index.ANALYZED));
            iw.addDocument(doc);
            iw.close();

            //第二步,查询索引,返回结果
            IndexReader ir = DirectoryReader.open(dir);

            //定义IndexSearcher
            IndexSearcher is = new IndexSearcher(ir);

            //定义Term,new Term("doc", "home"),第一个值表示要搜索的域,第二个则表示搜索值
            Term term = new Term("doc", "home");

            //TermQuery继承自Query抽象类,是Lucene最基本的查询
            Query query = new TermQuery(term);

            //执行查询,返回TopDocs对象结果集
            TopDocs td = is.search(query, 10);

            for(int i=0;i<td.scoreDocs.length;i++){
                Document d = is.doc(td.scoreDocs[i].doc);
                System.out.println("----------"+d.getField("title"));
                System.out.println("----------"+d.getField("content"));
                System.out.println("----------"+d.getField("doc"));
            }
            dir.close();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

}
索引的创建、修改和删除

首先,我们来看一个例子:开源中国社区每天都有人发布新的博客,同时也有很多人在进行修改和删除博客的操作。如果我们只更新博客数据而不更新对应的索引数据,这会带来那些问题呢?

新增的博客信息不能够及时被用户搜索到;

修改的博客信息查询时依然显示之前的内容;

删除的博客信息查询时存在但实际已被删除。

因此,为了提高系统搜索的准确性和实时性,我们在进行数据更新的同时,也会更新与之对应的索引数据,这样业务数据就可以保持与索引数据的一致,上面的几个问题也就随之解决了。

首先,我们来看新增索引的操作,这个比较简单,之前的例子里面已经有讲到:

//当新增博客时,索引也增量更新
public void addLuceneIndex(Blog blog){

    try {
        IndexWriter writer = new IndexWriter(directory, config);
        Document doc = new Document();

        //文章id,需要存储,查询结果的链接需要,但不需要检索
        doc.add(new Field("id",blog.getString("id"),Field.Store.YES,Field.Index.NO));

        //文章标题,需要存储也需要切词索引
        doc.add(new Field("title",blog.getString("title"),Field.Store.YES,Field.Index.ANALYZED));

        //文章内容一般会比较长,所以不需要存储,但需要切词索引
        doc.add(new Field("content",blog.getString("content"),Field.Store.NO,Field.Index.ANALYZED));

        //文章作者,需要存储,整体索引但不切词
        doc.add(new Field("author",blog.getString("author"),Field.Store.YES,Field.Index.NOT_ANALYZED));
        writer.addDocument(doc);
        writer.forceMerge(1);
        writer.commit();
  } catch (IOException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
  }
}
当博客被修改时,对应索引也执行更新操作,实际后台代码执行的是先删除再新增操作。

//索引更新操作
public void updateLuceneIndex(Blog blog){
    try {
        IndexWriter writer = new IndexWriter(directory, config);
        Document doc = new Document();
        writer.updateDocument(new Term("id", blog.getString("id")), doc);
        writer.forceMerge(1);
        writer.commit();
    } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
}
当文章删除时,对应索引也执行删除操作

//索引删除操作
public void delLuceneIndex(Blog blog){
    try {
        indexWriter.deleteDocuments(new Term("id", blog.getString("id")));  // Document删除
    } catch (IOException e) {
        e.printStackTrace();
    }
}
最后说明一下,索引文件的增、删、改在实际应用过程中也是有很多策略的。比如对于搜索实时性要求比较高的系统,可以采取实时更新的策略,在更新记录时同时更新索引;如果系统对搜索的实时性要求不高,且服务器资源有限,可以设置一个定时任务,把白天更新的记录都标记出来,在凌晨服务器空闲的时候批量更新。总之,可以根据自己的需要去灵活的应用。

分词(切词)

分词也叫作切词,是指把文档的内容按照一定的规则切分成一个个独立的词语,通俗的说就是把句子切分成词语。分词是影响Lucene查询效率和查询准确率的关键因素。所有的分词器都继承自Lucene的Analyzer,今天介绍最流行和通用的中文分词器IKAnalyzer的使用。

Lucene默认实现的有英文分词。英文分词相对简单,主要是对每个单词的单复数,时态等做转换即可。而中文分词相对更复杂一些。因为中文的词库本身就非常庞杂,同一个句子可能有好几种分词法,不同的分词法可能就会导致不同的查询结果。IKAnalyzer为我们解决以上问题提供了很好的方案,它允许我们可以个性化定义扩展词库,而且分词效率极高。

下面我们来看下IKAnalyzer的配置文件IKAnalyzer.cfg.xml,把它放置到源文件根目录下面,系统会自动加载进来。

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">
<properties>
    <comment>IKAnalyzer扩展配置</comment>

    <!--用户可以在这里配置自己的扩展字典-->
    <entry key="ext_dict">
        /com/jfinal/lucene/ext.dic;
        /com/jfinal/lucene/ft_main2012.dic;
        /com/jfinal/lucene/ft_quantifier.dic;
    </entry>

    <!--用户可以在这里配置自己的扩展停止词字典-->
    <entry key="ext_stopwords">
        /com/jfinal/lucene/stop.dic
    </entry>

</properties>
ext.dic用来定义自己的扩展词库。比如特定的地名,人名,就相当于告诉分词器如果遇到这些词汇就把它们做单独分词;

stop.dic用来定义自己的扩展停止词字典,停止词就是指那些最普通的,没有特定含义的词。比如英语里面的a ,the,汉语里面的了,又等等。

把IKAnalyzer的jar包拷贝到lib下,使用时新建对象即可。

Analyzer analyzer = new IKAnalyzer()
时间: 2024-07-31 14:26:17

Lucene学习总结的相关文章

lucene学习笔记(三)

好几天没更新了.更新一下,方便自己和大家学习. 这是最基本的代码 package index; import java.io.File; import java.io.IOException; import java.util.HashMap; import java.util.Map; import org.apache.lucene.analysis.standard.StandardAnalyzer; import org.apache.lucene.document.Document;

lucene学习笔记(二)

package index; import java.io.File; import java.io.IOException; import org.apache.lucene.analysis.standard.StandardAnalyzer; import org.apache.lucene.document.Document; import org.apache.lucene.document.Field; import org.apache.lucene.index.CorruptIn

lucene学习-创建索引

本文的lucene是基于lucene3.5版本. 使用lucene实现搜索引擎开发,核心的部分是建立索引和搜索.本节主要是记录创建索引部分的内容. 创建的索引结构如图所示. 创建索引的步骤分为以下几个步骤: 1.建立索引器IndexWriter 2.创建文档对象Document 3.建立信息对象字段Field 4.将Field对象添加到Document 5.将Document对象添加到IndexWriter对象中 下面简要介绍几个核心对象. (1).创建IndexWriter对象. IndexW

Lucene 5.2.1 + jcseg 1.9.6中文分词索引(Lucene 学习序列2)

Lucene 5.2.1 + jcseg 1.9.6中文分词索引(Lucene 学习序列2) jcseg是使用Java开发的一个开源的中文分词器,使用流行的mmseg算法实现.是一款独立的分词组件,不是针对lucene而开发,但是提供了最新版本的lucene和solr分词接口. Java Code <span style="font-size:14px;">package com.qiuzhping.lucene; import java.sql.Connection; i

Lucene学习笔记(1)

下载:http://lucene.apache.org lucene项目的Java子项目:http://lucene.apache.org/java Lucene学习笔记 查询者输入查询条件,条件之间可以通过特定运算符进行运算,比如查询希望查询到与“中国”和“北京”相关的记录,但不希望结果中包括“海淀区中关村”,于是输入条件为“中国+北京-海淀区中关村”: 把IndexWriter想象成让你可以对索引进行写操作的对象. 在一个文档被索引之前,首先需要对文档内容进行分词处理,并且而剔除一些冗余的词

Lucene学习笔记: 五,Lucene搜索过程解析

一.Lucene搜索过程总论 搜索的过程总的来说就是将词典及倒排表信息从索引中读出来,根据用户输入的查询语句合并倒排表,得到结果文档集并对文档进行打分的过程. 其可用如下图示: 总共包括以下几个过程: IndexReader打开索引文件,读取并打开指向索引文件的流. 用户输入查询语句 将查询语句转换为查询对象Query对象树 构造Weight对象树,用于计算词的权重Term Weight,也即计算打分公式中与仅与搜索语句相关与文档无关的部分(红色部分). 构造Scorer对象树,用于计算打分(T

Lucene 学习入门

Lucene 4.9 基础准备 了解常用分词器,选择合适分词器 读取文件编码要正确,非TXT文档需要进行特殊处理或特殊工具读取后才进行分词处理 TextField内容不能保存过长,最大长度是32766个字节 StringField, TextField 的区别,其他 StringField 不进行分词处理,保存 TextField 进行分词处理,默认不保存,可以选择保存,最大长度是 32766字节 其他省略- Demo参考: org.apache.lucene.demo.IndexFiles o

Lucene学习笔记

师兄推荐我学习Lucene这门技术,用了两天时间,大概整理了一下相关知识点. 一.什么是Lucene Lucene即全文检索.全文检索是计算机程序通过扫描文章中的每一个词,对每一个词建立一个索引,指明该词在文章中出现的次数和位置.当用户查询时根据建立的索引查找,类似于通过字典的检索字表查字的过程. 二.Lucece全文检索和数据库检索的区别 三.Lucene的原理 (1)索引库操作原理 注意:这里面有两个关键的对象:分别是IndexWriter和IndexSearcher. 执行增删改操作用的是

Lucene 学习之一:源码环境搭建

一直想抽点时间系统的学习下Lucene ,今天把Lucene 源码学习环境搭建了一下.下面描述一下环境搭建过程. 开发环境的配置(lucene-4.10.2 + Eclipse): 1:下载最新源码:把jar包lucene-4.10.2,和java源码lucene-4.10.2-src 都下载下来. 下载地址:http://mirror.bit.edu.cn/apache/lucene/java/4.10.2/ 2:在Eclipse 安装lucene-4.10.2 java源码. 新建JAVA

lucene学习 - 2 - 一个示例

接下来我会写一个lucene的实例.实际上在搜索引擎上随便搜索下都能找到这样的东西.不过还是写一下吧,这也是我学习的经历. package com.zhyea.doggie; import java.io.BufferedReader; import java.io.File; import java.io.FileReader; import java.io.IOException; import org.apache.lucene.analysis.Analyzer; import org.