`

lucene全文检索实施方案

阅读更多
  • 为什么要使用全文索引技术?

 

在网站应用中,我们经常需要用到站内搜索的功能来查找指定的关键字。在网站的后台

存储中,信息可能存储的地方主要有:数据库表、HTML静态页面文件、word、pdf、excel、ppt、txt等文本文件中。

基于文件的全文检索当然是使用分词技术来实现。在Java开源产品中,Lucene是一个使用最广泛的全文搜索引擎,我们可以使用Lucene的API将文本的内容进行分词处理。经分词处理后,Lucene会将解析的分词增加到文件索引库中,然后我们可以通过分词查询技术,将与查询内容相关的文件检索出来。

那么对于数据库的全文检索如何实现?在企业的网站中,大量的动态信息是存储在数据库中的,例如新闻内容、知识库、商品信息等都是存储在数据库表中的。如果我们使用数据库的like ‘%关键词%’这种方式查找信息显然是不可取的,因为数据库对于like ‘%关键词%’这种查询模式,数据库索引是起不到效果的,这样会严重影响查询的效率。所以对于数据库的全文检索,也应使用分词技术,在增加表记录的时候,将相关字段采用Lucene的分词技术增加到索引库中,并同时将记录的ID和对应的访问连接也同时加入到索引库中,我们就可以在查询关键词的时候,将对应信息的访问连接同时查找出来,这样就起到全文检索的效果。

 

  • 网站内容管理系统(CMS)全文检索技术实现

 

在网站内容管理系统中,信息的正文一般是存储在数据库表中,信息表的结构一般包括

信息ID、标题、摘要、正文、所属栏目、关键词、作者、来源等字段。在信息发布的流程中,主要包括信息的编辑、送审、审批、发布、取消发布、信息删除等环节。信息正式发布的时候,除了需要生成此信息对应的html文件,还要将对信息的标题、摘要、正文等字段进行分词处理,这是为了在信息发布以后,可通过站内搜索功能,将查询内容关联的信息条目查找出来。在删除信息或取消发布时,还要将对应信息的分词从索引库中删除。

因为操作索引库的同时Lucene会对索引文件加锁,所以增加和删除索引库会导致并发问题,一旦索引库被锁定,则其他用户发布信息的时候就不能将词条增加到索引库中,所以我们在信息发布和取消发布的时候,只需要把发布或删除的信息记录到索引库待处理队列中,由定时器定时处理。

整个全文检索的实现需要设计以下功能:

 

  • 索引库初始化工具:清空索引库,主要用于系统初始化的时候。
  • 定时器及索引队列:定时处理索引队列,对增加的信息,向索引库中添加分词,对删除或取消发布的信息,从索引库中删除分词。
  • 分词处理:主要用于添加分词、删除分词。对于内容管理系统而言,如果一篇文章如果带有word等附件,附件的正文也要参与分词处理。
  • 分词查询:提供带分页功能的关键词查找。

 

下面具体介绍全文检索功能的实现:

 

  • 索引库初始化:指定一个目录,创建Lucene的分词库文件。全文检索必须有索引库文件才能进行增加索引、删除索引和进行索引查询等操作。下面是初始化分词库代码:

 

    public static void initIndex(String dir) throwsCorruptIndexException, LockObtainFailedException, IOException

    {

        IndexWriter writer;   // new index being built

        try

        {

        File file = newFile(dir);

        file.mkdirs();

        }

        catch(Exception ex)

        {

        logger.error("创建目录失败!");

        }

       writer = newIndexWriter(FSDirectory.open(newFile(dir)), newStandardAnalyzer(Version.LUCENE_CURRENT), true,

                newIndexWriter.MaxFieldLength(1000000));

       writer.optimize();

       writer.close();

    }

 

 

(2) 索引队列数据库设计:

 

索引队列表Comm_Lucene_queue的表结构(只列出主要字段):

 

 

字段

字段中文名

字段说明

Entity_name

表名

对于内容管理系统,主要是信息表需要处理全文检索,但系统还需支持对其他数据库表进行全文检索,所以设置一个表名字段用于区分

Entity_row_id

记录ID

记录要处理的表的哪条记录,用唯一行号区分。

Index_oper_type

全文检索处理方式

标识增加分词用add,标识删除分词用delete

Create_dt

队列创建时间

记录本条队列创建的日期+时分秒+毫秒,用于标识处理顺序

 

 

 

 

全文检索的定时器只需要定时处理这个数据库表的队列信息就可以了,处理完毕后,删除已处理的记录。定时器可以设置每几分钟读取几千条队列信息进行处理,处理队列信息就是根据index_oper_type来区分是增加分词还是删除分词,然后根据entity_name和row_id来确认处理哪个数据库表的哪条记录。因为对于信息表,在设计时就已经确认需要对标题、摘要、正文等字段进行分词,那么如果对于其他数据库表,系统如何知道哪些表的哪些字段需要分词呢?我们可以单独设置一个表字段信息配置表来标识哪些表哪些字段需要分词。下面是对数据库表字段基本信息表中增加的全文检索设置字段:

 

 

字段

字段中文名

字段说明

Table_name

数据库表名

 

Column_name

表字段名

 

Is_search

是否参与全文检索

如果字段参与全文检索,则需要设置是否分词和是否在索引库中存储字段值。

Is_lucene_analyzed

是否做分词解析

对于全文检索,如作者,信息ID,创建时间,对应的url都不需分词解析,因为这些字段拆分是没意义的,但需要存储到索引库

Is_lucene_indx

是否存储分词

对于大文本的正文一般只做分词,不存储。例如对于信息表,正文字段做分词处理,但不存储,信息ID做存储(存储在索引库而不是数据库),但不分词。

 

在这里顺便说明一下索引库的优化,因为Lucene索引库的增加和删除都需要打开和关闭索引文件,所以在处理索引队列时,不是每读一条记录就打开和关闭一次索引库,而是首先打开索引文件,然后按队列的记录信息逐条做增加或删除分词,知道本次查询的所有队列处理完毕后再优化和关闭索引文件。见下面的代码:

//第一步:首先打开索引文件

String indexPath = ServiceLocator.getSysConfigService().getStringValueByParmName("luceneIndexDir");//伪代码


IndexWriter writer = null;

writer = newIndexWriter(FSDirectory.open(newFile(indexPath)), newStandardAnalyzer(Version.LUCENE_CURRENT),false,

                     newIndexWriter.MaxFieldLength(1000000));

writer.setMergeFactor(100);

writer.setMaxBufferedDocs(50);

writer.setMaxMergeDocs(2000);

//第二步:索引队列处理(代码略)

//第三步:优化和关闭索引库

writer.optimize();//优化索引库

writer.close();   //关闭索引库

……

 

 

(3)分词处理

 

【删除分词】

关于分词的删除比较简单,当信息记录删除后,根据信息记录的唯一行号在分词库中查到对应的记录,然后删除分词:

String indexPath = ServiceLocator.getSysConfigService().getStringValueByParmName("luceneIndexDir");

String filePath = ServiceLocator.getSysConfigService().getStringValueByParmName("searchRoot");

Query query = null;   

IndexReader reader = IndexReader.open(FSDirectory.open(newFile(indexPath)), true);

IndexSearcher searcher = null;    

searcher = newIndexSearcher(reader);

Analyzer analyzer = newStandardAnalyzer(Version.LUCENE_CURRENT); 

//根据信息id查找对应的索引条目

QueryParser qp = newQueryParser(Version.LUCENE_CURRENT,"id", analyzer);

query = qp.parse(infoId);

//删除对应的索引

writer.deleteDocuments(query);

  

【增加分词】

在信息发布过程中,每条发布的信息已生成了对应的静态页面,为了让访问网站的用户能够在站内搜索中根据查询关键字查找到这条信息,需要增加此信息对应的分词,因为发布信息时,系统会往索引处理队列中插入记录,所以如果从队列中读取到标识为”add”的记录,就会执行增加分词操作,增加分词的基本处理逻辑就是根据信息ID,找到数据库中对应的记录,然后将表字段的值赋予给Lucene的Field(域),然后构造一个Lucene特有的Document对象写入到索引库中。看下面的代码片段:

 

//首先创建一个Document对象。

Document doc = newDocument();

IndexReader reader = IndexReader.open(FSDirectory.open(newFile(indexPath)), true);

Analyzer analyzer = newStandardAnalyzer(Version.LUCENE_CURRENT); 

//添加Path域,这个非常重要,实际值是此信息对应的URL访问连接。Path域不需要分词,但//要存储,Index.NOT_ANALYZED表示不需要分词,Field.Store.YES表示需存储。

doc.add(newField("path", infEnt.getInfUrl(), Field.Store.YES,Field.Index.NOT_ANALYZED));

//增加标题域,信息在页面中显示的标题文字

doc.add(newField("title", infEnt.getInfTitle(), Field.Store.YES, Field.Index.ANALYZED));

//增加摘要域,Field.Store.YES表示需存储,Field.Index.ANALYZED表示需分词。

String summary = infEnt.getInfSummary();

if(summary==null)summary="";//空值是不能建立索引的

doc.add(newField("summary", summary, Field.Store.YES, Field.Index.ANALYZED));//或者取正文的某段做摘要。

……

//对于正文的处理:获取信息表的正文字段,如果有附件,根据附件格式//(word,pdf,excel,ppt,txt等)调用对应的正文读取器获取这些文件的正文,再加上信息//表的正文作为contents域的值参与分词解析,这样查询时,无论是正文还是附件,只要有对//应的关键词都可以被检索出来。如果信息是一个外部连接,可使用org.htmlparser包的API将对应html连接的正文获取下来,加入到contents中。

doc.add(newField("contents", buffer.toString(), Field.Store.NO, Field.Index.ANALYZED));//其中bugger.toString()是正文+附件的内容。

 

//增加ID表示域,增加这个用于区分对哪个索引条目进行处理,删除信息时,需要查找id值以便删除对应的索引分词。

doc.add(newField("id", infoId, Field.Store.NO, Field.Index.NOT_ANALYZED));

//将增加的索引分词添加到索引库

writer.addDocument(doc);

 

 

说明:Field域的标识是可以自己定义的,如上面的title,path,contents域,具体根据业务需要来定义,但定义的域一般都需要在编程中使用,否则就没有意义。

 

(4)分词查询

 

分词查询实际就是全文检索的最终目标,可以在网站的页面上输入关键词进行全文检索,简单的站内检索一般是针对正文关键词进行检索,如果设计的复杂一点,还可以按标题、作者、发布日期、摘要、信息分类等进行全文检索。分词查询需要实现:搜索条件输入页面、查询结果页面(带分页的)、后台分词查询算法。

一般首页、主要的二级页面都有站内搜索的输入框,如下图:

 

点击搜索后,系统将搜索参数提交到MVC控制层中进行全文检索查询,查询后返回搜索的结果页面,搜索结果页面必须是带分页功能,因为查询出来的匹配的记录可能会很多,另外搜索出来的每条信息都应有标题、摘要、查询出来符合条件的记录数,点击信息标题后可以连接到详细信息的查看页面。通过全文检索查询的效率比数据库直接查询效率会高出很多,查询出几万条符合条件记录需要的时间基本都在毫秒级。见下图查询结果页:

对Lucene的全文检索效率可到http://www.culturalink.gov.cn/中国文化网的首页上体验一下查询效率,使用“中国”作为查询内容大概可查到两万多条记录。

 具体的分词查询和分页算法的代码就不在这里赘述了。

 

  • 带权限的全文检索

 

带权限的全文检索的实现也比较简单,可以首先设置每条信息应该归什么权限访问,例如某条信息的可以由AUTH_1,AUTH_2权限码访问,则在增加索引库的时候可添加一个名为auth_id的Field域,域的值为按逗号隔开的权限码,如auth_1,auth_2,在信息查询的时候,检查当前用户的权限集合是否有这些权限,在分词查询逻辑中增加对auth_id域的权限判断,就可以过滤掉自己无权查看的记录。

分享到:
评论
1 楼 zhenglongfei 2012-09-23  
lz请教一个问题。我在插入内容的时候,已经将内容的标题contentName压入到索引文件中,为什么我在前台输入标题搜索,总是搜索不出来??


代码:doc.add(new Field(LuceneUtil.CONTNAME, content.getContname(), Field.Store.YES,Field.Index.ANALYZED));


请楼主指教。。。

相关推荐

    Lucene 全文检索实践.pdf

    Lucene是Apache Jakarta项目中的一个子项目,它提供了一套高效、灵活的全文检索解决方案。作为一个开源的文本搜索库,Lucene允许开发者轻松地为各种类型的数据源(如文件、数据库等)构建全文检索功能。 ##### 特性...

    一种基于Lucene检索引擎的全文数据库的研究与实现

    本文探讨了一种基于Lucene检索引擎的全文数据库的实现方案,通过将全文检索技术与文件系统相结合,有效地解决了非结构化文本数据的管理和检索问题。这种方法不仅提高了检索效率,还降低了系统的复杂度,对于需要处理...

    针对中文检索的Lucene改进策略

    Lucene作为一款广泛使用的开源全文检索工具包,其默认的语言处理机制(如单字切分、双字切分)在处理中文时存在一定的局限性。本文探讨了一种针对中文检索的Lucene改进策略,旨在提高基于Lucene中文检索系统的检索...

    全文检索需求及选型

    本文将从需求分析出发,详细介绍两种常见的全文检索技术——Lucene与Autonomy,并对这两种技术进行对比分析,旨在为企业提供选型建议。 #### 需求分析 在档案管理系统和知识管理系统中,全文检索的需求主要体现在...

    基于Lucene的搜索引擎在Struts中的应用.pdf

    Lucene是一个用Java编写的开源全文检索引擎工具包,它不是完整的应用,而是一系列用于构建全文索引和执行检索操作的类库。通过将Lucene嵌入到应用程序中,可以实现对特定应用内容的全文索引和检索功能。Lucene由多个...

    基于文本聚类与分布式Lucene的知识检索.pdf

    传统的集中式索引方法,如Lucene检索框架,虽然采用了高度优化的倒排索引结构,在处理大量非结构化文本知识时,索引时间会显著增长,同时巨大的索引文件也会导致性能瓶颈。这种集中式索引在面临海量数据时,效率和...

    传智播客Lucene3.0课程

    ### 传智播客Lucene3.0课程知识点解析 #### 一、全文检索概览 **全文检索**是一种能够高效地从大量文档...学习Lucene不仅能帮助开发者理解全文检索的工作原理,还能掌握如何在实际项目中实施高效的信息检索解决方案。

    lucene对数据库操作

    Lucene是一个开源全文检索库,由Apache软件基金会开发。它为开发者提供了强大的文本搜索功能,但不直接处理数据库操作。然而,Lucene可以与数据库结合使用,以实现高效的全文搜索和索引。在这个主题中,我们将深入...

    厦门人才网分布式全文检索与推荐系统设计.pdf

    ***是Lucene在.NET环境下的一个移植版本,它为.NET开发人员提供了全文索引和检索功能,继承了Java下Lucene的高效性。在***框架下,系统实现了如下功能: ***.Analysis模块:主要负责言语分析,即切词工作。对于中文...

    lucene in action 2

    实际上,Lucene内部采用了许多高级的信息检索技术。 - **API设计**:Lucene的索引和搜索API设计得非常周到,使得用户无需深入了解其内部工作原理即可开始使用。 #### 二、通用搜索应用架构 - **整体架构**:在本...

    [搜索链接]java(结合lucene)版的公交搜索系统_javaso.zip

    总的来说,这个 Java 结合 Lucene 的公交搜索系统展示了如何利用 Java 的面向对象特性与 Lucene 的全文检索能力,为公共交通查询提供一个高效、用户友好的解决方案。通过对数据的智能管理和搜索算法的设计,系统能够...

    ASP.NET基于Ajax+Lucene构建搜索引擎的设计和实现(源代码+论文).rar

    7. **论文**:通常,毕业设计会包含一篇详细的技术论文,解释设计思路、实施过程、遇到的问题以及解决方案。这篇论文将提供理论背景、技术细节和项目评估,对学习者来说是非常宝贵的参考资料。 综上所述,这个项目...

    ASP.NET基于Ajax+Lucene构建搜索引擎的设计和实现_project.rar

    本项目"ASP.NET基于Ajax+Lucene构建搜索引擎的设计和实现_project"旨在提供一种解决方案,利用现代Web技术和开源全文搜索引擎库来创建用户友好的搜索体验。 首先,ASP.NET是Microsoft开发的一个用于构建动态Web应用...

    【重要】Lucene多线程操作实现[定义].pdf

    在软件开发领域,尤其是涉及到全文搜索引擎的构建时,...总之,理解并正确实施Lucene的多线程规则和最佳实践对于构建高效、稳定的搜索引擎应用至关重要。开发者应确保遵循这些规则,以避免潜在的数据冲突和性能问题。

    Lucene Server-开源

    Lucene是一个全文检索库,由Java编写,它提供了文本分析、索引创建、搜索以及其他相关功能。Lucene的核心特性包括倒排索引、分词器、过滤器和查询解析器,这些使得它能够快速地对大量文本数据进行搜索。而Lucene ...

    ELK整体解决方案实施步骤

    ### ELK整体解决方案实施步骤 #### 一、概述 ELK Stack是由三个强大的开源工具——Elasticsearch、Logstash 和 Kibana 组成的技术栈,用于实现日志的集中化管理和分析。其中,Logstash 主要负责日志数据的采集与...

    ASP.NET基于Ajax+Lucene构建搜索引擎的设计和实现(源代码+论文).zip

    在本项目中,"ASP.NET基于Ajax+Lucene构建搜索引擎的设计和实现",我们将探讨如何利用这两种技术来创建一个高效且用户友好的搜索解决方案。 Ajax(Asynchronous JavaScript and XML)是一种在不刷新整个页面的情况...

    IR-project-.zip

    Lucene是Apache软件基金会下的一个开源全文检索库,它提供了高效的文本索引和搜索功能。在本项目中,Lucene作为核心框架,负责新闻数据的索引构建、查询解析和结果返回。通过对新闻内容进行分词、建立倒排索引,...

    基于Solr的分布式铁路科技资源整合与检索实践.pdf

    Solr是一个高性能的搜索服务器,它基于Apache Lucene构建,提供了分布式索引、搜索、排名等功能,广泛应用于企业级搜索解决方案中。文中提到,为了解决铁路科技信用与能力评价中面临的问题,如科研活动信息分散、...

Global site tag (gtag.js) - Google Analytics