Lucene实践心得笔记

栏目: 编程工具 · 发布时间: 8年前

内容简介: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()

--------------------------------------分割线 --------------------------------------

基于Lucene多索引进行索引和搜索 http://ww w.linuxidc.com/Linux/2012-05/59757.htm

Lucene 实战(第2版) 中文版 配套源代码 http://www.linuxidc.com/Linux/2013-10/91055.htm

Lucene 实战(第2版) PDF高清中文版 http://www.linuxidc.com/Linux/2013-10/91052.htm

使用Lucene-Spatial实现集成地理位置的全文检索 http://www.linuxidc.com/Linux/2012-02/53117.htm

Lucene +Hadoop 分布式搜索运行框架 Nut 1.0a9 http://www.linuxidc.com/Linux/2012-02/53113.htm

Lucene + Hadoop 分布式搜索运行框架 Nut 1.0a8 http://www.linuxidc.com/Linux/2012-02/53111.htm

Lucene + Hadoop 分布式搜索运行框架 Nut 1.0a7 http://www.linuxidc.com/Linux/2012-02/53110.htm

Project 2-1: 配置Lucene, 建立WEB查询系统[Ubuntu 10.10] http://www.linuxidc.com/Linux/2010-11/30103.htm

--------------------------------------分割线 --------------------------------------

Lucene 的详细介绍 请点这里

Lucene 的下载地址 请点这里

本文永久更新链接地址 http://www.linuxidc.com/Linux/2017-03/141902.htm


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

PHP项目开发全程实录

PHP项目开发全程实录

清华大学出版社 / 2008 / 56.00元

《软件项目开发全程实录丛书•PHP项目开发全程实录:DVD17小时语音视频讲解(附光盘1张)》主要特色: (1)12-32小时全程语音同步视频讲解,目前市场上唯一的“全程语音视频教学”的案例类 图书,培训数千元容,尽在一盘中! (2)10套“应用系统”并公开全部“源代码”,誓将案例学习进行到底! (3)丛书总计80个应用系统300个应用模块。 (4)含5000页SQL se......一起来看看 《PHP项目开发全程实录》 这本书的介绍吧!

XML 在线格式化
XML 在线格式化

在线 XML 格式化压缩工具

HEX CMYK 转换工具
HEX CMYK 转换工具

HEX CMYK 互转工具

HSV CMYK 转换工具
HSV CMYK 转换工具

HSV CMYK互换工具