阿里云-云小站(无限量代金券发放中)
【腾讯云】云服务器、云数据库、COS、CDN、短信等热卖云产品特惠抢购

Lucene实践心得笔记

127次阅读
没有评论

共计 6027 个字符,预计需要花费 16 分钟才能阅读完成。

在使用 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://www.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

正文完
星哥说事-微信公众号
post-qrcode
 
星锅
版权声明:本站原创文章,由 星锅 2022-01-21发表,共计6027字。
转载说明:除特殊说明外本站文章皆由CC-4.0协议发布,转载请注明出处。
【腾讯云】推广者专属福利,新客户无门槛领取总价值高达2860元代金券,每种代金券限量500张,先到先得。
阿里云-最新活动爆款每日限量供应
评论(没有评论)
验证码
【腾讯云】云服务器、云数据库、COS、CDN、短信等云产品特惠热卖中