lucene全文检索案例

最近工作中使用到的全文检索案例,分享下。使用lucene最新版本为3.6,该案例是从磁盘文档建立索引,如下介绍:

lucene简介

Lucene是一套用于全文检索和搜寻的开源程式库,由Apache软件基金会支持和提供。Lucene提供了一个简单却强大的应用程式接口,能够做全文索引和搜寻,在Java开发环境里Lucene是一个成熟的免

费开放源代码工具;就其本身而论,Lucene是现在并且是这几年,最受欢迎的免费java资讯检索程式库。人们经常提到资讯检索程式库,就像是搜寻引擎,但是不应该将资讯检索程式库与网搜索引擎相混淆

索引和搜索的一些概念的介绍:

假设我们的电脑的目录中含有很多文本文档,我们需要查找哪些文档含有某个关键词。为了实现这种功能,我们首先利用 Lucene 对这个目录中的文档建立索引,然后在建立好的索引中搜索我们所要查找的文档

Document

Document 是用来描述文档的,这里的文档可以指一个 HTML 页面,一封电子邮件,或者是一个文本文件。一个 Document 对象由多个 Field 对象组成的。可以把一个 Document 对象想象成数据库中的一个记录,而每个 Field 对象就是记录的一个字段。

Field

Field 对象是用来描述一个文档的某个属性的,比如一封电子邮件的标题和内容可以用两个 Field 对象分别描述。

Analyzer

在一个文档被索引之前,首先需要对文档内容进行分词处理,这部分工作就是由 Analyzer 来做的。Analyzer 类是一个抽象类,它有多个实现。针对不同的语言和应用需要选择适合的 Analyzer。Analyzer 把分词后的内容交给 IndexWriter 来建立索引。

IndexWriter

IndexWriter 是 Lucene 用来创建索引的一个核心的类,他的作用是把一个个的 Document 对象加到索引中来。

Directory

这个类代表了 Lucene 的索引的存储的位置,这是一个抽象类,它目前有两个实现,第一个是 FSDirectory,它表示一个存储在文件系统中的索引的位置。第二个是 RAMDirectory,它表示一个存储在内存当中的索引的位置

Query

这是一个抽象类,他有多个实现,比如 TermQuery, BooleanQuery, PrefixQuery. 这个类的目的是把用户输入的查询字符串封装成 Lucene 能够识别的 Query。

Term

Term 是搜索的基本单位,一个 Term 对象有两个 String 类型的域组成。生成一个 Term 对象可以有如下一条语句来完成:Term term = new Term(“fieldName”,”queryWord”); 其中第一个参数代表了要在文档的哪一个 Field 上进行查找,第二个参数代表了要查询的关键词。

IndexSearcher

IndexSearcher 是用来在建立好的索引上进行搜索的。它只能以只读的方式打开一个索引,所以可以有多个 IndexSearcher 的实例在一个索引上进行操作

首先要导入的包有:

                lucene-core-3.6.1.jar    lucene核心包

                IKAnalyzer3.2.8.jar      中文分词器包

                lucene-highlighter-3.5.0.jar    高亮包

                lucene-memory-3.5.0.jar    lucene架包

                lucene-analyzers-3.5.0.jar   用于分词 建立索引的jar包

操作类代码(MyLuceneUtil):

package cn.voole.util;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.IndexWriterConfig;
import org.apache.lucene.index.Term;
import org.apache.lucene.index.IndexWriterConfig.OpenMode;
import org.apache.lucene.queryParser.QueryParser;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.ScoreDoc;
import org.apache.lucene.search.TopDocs;
import org.apache.lucene.search.highlight.Highlighter;
import org.apache.lucene.search.highlight.QueryScorer;
import org.apache.lucene.search.highlight.SimpleFragmenter;
import org.apache.lucene.search.highlight.SimpleHTMLFormatter;
import org.apache.lucene.store.FSDirectory;
import org.apache.lucene.util.Version;
import org.wltea.analyzer.lucene.IKAnalyzer;
public class MyLuceneUtil {

 private static File index_file =null;
 private static Analyzer analyzer = null;
 private static MyLuceneUtil lucence = new MyLuceneUtil();
 private static boolean havapath;
 private static QueryParser parser ;
 
 private int textmaxlength = 200;
 private static String prefixHTML = "<font color='red'>";
 private static String suffixHTML = "</font>";
 
 /** 初始化工具 **/
 private MyLuceneUtil(){
  System.out.println("lucence初始化开始....");
  analyzer = new IKAnalyzer();
  index_file = new File("d:\\lucene-index");
  havapath = (index_file.list().length>=0);
  parser = new QueryParser(Version.LUCENE_36, LucenceVo.TITLE,
    analyzer);
 }

 /** 返回一个单例 **/
 public static MyLuceneUtil instance(){
  return lucence;
 }
 
 /**
  * 索引库中查询
  * @param keyword
  * @return
  * @yijianfeng
  */
 public List<LucenceVo> searchIndex(String keyword,int start,int size)  {
  IndexSearcher searcher = null;
  List<LucenceVo> list = new ArrayList<LucenceVo>();
  if(!havapath){
   return list;
  }
  try {
   IndexReader reader = IndexReader.open(FSDirectory.open(index_file));
   searcher = new IndexSearcher(reader);
   Query query =parser.parse(keyword);
   TopDocs topDocs = searcher.search(query, (size+start));
   ScoreDoc[] scoreDocs = topDocs.scoreDocs;
   int end = (size+start)<topDocs.totalHits?(size+start):topDocs.totalHits;
   for (int i = start; i < end; i++) {
    Document doc = searcher.doc(scoreDocs[i].doc);
    LucenceVo info = new LucenceVo();
    //关键词加亮
    SimpleHTMLFormatter simpleHTMLFormatter = new  SimpleHTMLFormatter(prefixHTML, suffixHTML);
    Highlighter highlighter = new  Highlighter(simpleHTMLFormatter, new QueryScorer(query));
    highlighter.setTextFragmenter(new SimpleFragmenter(textmaxlength));
    String DESCRIPTION = highlighter.getBestFragment(analyzer,LucenceVo.DESCRIPTION,doc.get(LucenceVo.DESCRIPTION));
    String TITLE = highlighter.getBestFragment(analyzer,LucenceVo.TITLE,doc.get(LucenceVo.TITLE));
    if(DESCRIPTION==null)
    {
     info.setDescription(doc.get(LucenceVo.DESCRIPTION));
    }
    else
    {
     info.setDescription(DESCRIPTION);
    }
    //取消重复加亮节点
    TITLE = TITLE.replaceAll(suffixHTML+prefixHTML, "");
    DESCRIPTION = info.getDescription().replaceAll(suffixHTML+prefixHTML, "");
    //实体赋值
    info.setId(doc.get(LucenceVo.ID));
    info.setTitle(TITLE);
    info.setUrl(doc.get(LucenceVo.URL));
    list.add(info);
   }
  }catch (Exception e) {
   e.printStackTrace();
  }
  finally {
   if(searcher!=null)
   {
    try {
     searcher.close();
    } catch (IOException e) {
     e.printStackTrace();
    }
   }
  }
  return list;
 }

 /**
  * 添加列表到索引库中
  * @yijianfeng
  * @param list
  * @throws IOException
  */
 public void writeIndex(List<LucenceVo> list) throws IOException {
  IndexWriter writer = openIndexWriter();
  try {
   for (LucenceVo lucenceVo : list) {
    Document document = builderDocument(lucenceVo);
    writer.addDocument(document);
   }
  } finally {
   writer.close();
  }
 }

 /**
  * 添加单个到索引库中
  * @yijianfeng
  * @param LucenceVo
  * @throws IOException
  */
 public void writeIndex(LucenceVo vo) throws IOException {
  IndexWriter writer = openIndexWriter();
  try {
   Document document = builderDocument(vo);
   writer.addDocument(document);
  } finally {
   writer.close();
  }
 }
 
 /**
  * 删除所有索引库
  * @yijianfeng
  */
 @SuppressWarnings("deprecation")
 public void deleteAllIndex(boolean isdeletefile){
   IndexReader reader = null; 
         if(index_file.exists() && index_file.isDirectory()) { 
             try{ 
                 reader = IndexReader.open(FSDirectory.open(index_file),false);
                 for(int i = 0; i < reader.maxDoc(); i ++) { 
                     reader.deleteDocument(i);
                 } 
                 reader.close(); 
             } catch (Exception ex) {
                   ex.printStackTrace();
             } finally { 
                 if(reader != null) { 
                     try { 
                         reader.close(); 
                     } catch (IOException e) { 
                     } 
                 } 
             }
             deleteAllFile();
         } 
 }
 /**
  * 单条删除索引
  */
 @SuppressWarnings("deprecation")
 public void deleteIndexByTerm(String id)
 {
  IndexReader reader = null;
  if(index_file.exists() && index_file.isDirectory())
  {
   try{
    reader = IndexReader.open(FSDirectory.open(index_file),false);
    Term term = new Term("id",id);  
    reader.deleteDocuments(term); 
   }catch(Exception e)
   {
    e.printStackTrace();
   }finally{
    if(reader!=null)
    {
     try{
      reader.close();
     } catch (IOException e) { 
                    }
    }
   }
  }
 }
 
 /**
  * 单条更新索引
  * @throws IOException
  */
 public void updateIndexByTerm(LucenceVo vo) throws IOException
 {
  
  IndexWriter writer = openIndexWriter();
  try {
   Term term = new Term("id",vo.getId()); 
   Document doc = builderDocument(vo);
   writer.updateDocument(term, doc);
  } finally {
   writer.close();
  }
 }
 
 /**
  * 删除所有索引文件
  * @yijianfeng
  */
 public void deleteAllFile(){
  File[] files = index_file.listFiles();
  for (int i = 0; i < files.length; i++) {
   files[i].delete();
  }
 }

/**
  * 类IndexWriterConfig参数说明,第一个参数指定lucene的版本号,第二个参数指定了Analyzer一个实现,也就是指定
  * 这个索引是用哪个分词器对文档进行分词
  * 类IndexWriter参数说明,第一个参数指定所建索引存放的位置,可以是一个 File 对象,也可以是一个 FSDirectory 对象或者 RAMDirectory 对象
  * @return
  * @throws IOException
  */

 private IndexWriter openIndexWriter() throws IOException {
  IndexWriterConfig indexWriterConfig = new IndexWriterConfig(Version.LUCENE_36,
    analyzer);
  //索引 设置为追加或者覆盖
  indexWriterConfig.setOpenMode(OpenMode.CREATE_OR_APPEND);
  return new IndexWriter(FSDirectory.open(index_file), indexWriterConfig);
 }

 @SuppressWarnings("static-access")
 private Document builderDocument(LucenceVo lucenceVo) {
  Document document = new Document();
  Field id = new Field(lucenceVo.ID, String.valueOf(lucenceVo.getId()),
    Field.Store.YES, Field.Index.ANALYZED);
  Field TITLE = new Field(lucenceVo.TITLE, lucenceVo.getTitle(),
    Field.Store.YES, Field.Index.ANALYZED);
  Field DESCRIPTION = new Field(lucenceVo.DESCRIPTION, lucenceVo.getDescription(),
    Field.Store.YES, Field.Index.ANALYZED);
  Field TYPE = new Field(lucenceVo.TYPE, lucenceVo.getType(),
    Field.Store.YES, Field.Index.ANALYZED);
  Field URL = new Field(lucenceVo.URL, lucenceVo.getUrl(),
    Field.Store.YES, Field.Index.ANALYZED);
  document.add(id);
  document.add(TITLE);
  document.add(DESCRIPTION);
  document.add(TYPE);
  document.add(URL);
  return document;
 }
}       

 

bean类(LucenceVo)

package cn.voole.util;

public class LucenceVo {
 
 public static final String ID = "id";
 public static final String TITLE = "title";
 public static final String TYPE = "type";
 public static final String DESCRIPTION = "description";
 public static final String URL = "url";
 
 private String id;
 private String type;
 private String title;
 private String description;
 private String url;
 
 public String getId() {
  return id;
 }
 public void setId(String id) {
  this.id = id;
 }
 public String getType() {
  return type;
 }
 public void setType(String type) {
  this.type = type;
 }
 public String getTitle() {
  return title;
 }
 public void setTitle(String title) {
  this.title = title;
 }
 public String getDescription() {
  return description;
 }
 public void setDescription(String description) {
  this.description = description;
 }
 public String getUrl() {
  return url;
 }
 public void setUrl(String url) {
  this.url = url;
 }
 

}

测试类(test):

package cn.voole.util;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
public class test {

 /**
  * @param args
  */
 public static void main(String[] args) {
  testwirte();
  testsearch();
 }
 
 /**
  * 向索引库添加数据
  */
 public static void testwirte(){
  List<LucenceVo> list = new ArrayList<LucenceVo>();
  for (int i = 0; i < 10000; i++) {
   LucenceVo vo = new LucenceVo();
   vo.setId("myid"+i);
   vo.setTitle("中国今天新闻"+i);
   vo.setDescription("新闻关键字备注"+i);
   vo.setType("新闻");
   vo.setUrl("http://www.baidu.com/?id="+i);
   list.add(vo);
  }
  try {
   MyLuceneUtil.instance().writeIndex(list);
  } catch (IOException e) {
   e.printStackTrace();
  }
 }
 
 /**
  * 从索引库读取数据
  */
 public static void testsearch(){
  List<LucenceVo> list =  MyLuceneUtil.instance().searchIndex("今天", 0 , 10);
  for (int i = 0; i < list.size(); i++) {
   LucenceVo vo =  list.get(i);
   System.out.println(vo.getTitle()+"==="+vo.getDescription());
  }
  System.out.println(list.size());
 }

}

lucene性能优化

IndexWriter提供了一些接口可以控制建立索引的操作,另外我们可以先将索引写入RAMDirectory,再批量写入 FSDirectory,不管怎样,目的都是尽量少的文件IO,因为创建索引的最大瓶颈在于磁盘IO。另外选择一个较好的分析器也能提高一些性能。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
使用Lucene实现对MySQL数据表的全文检索是一种可行的方案。Lucene是一套开源的全文检索和搜寻的程式库,它提供了一个简单但强大的应用程式接口,能够实现全文索引和搜寻的功能。在Java开发环境中,Lucene是一个成熟的免费开源工具,被广泛应用于信息检索领域。 全文检索是一种针对非结构化数据的检索方法,对于像磁盘上的文件、网站资源等非结构化数据,无法使用SQL语句进行查询,因此需要使用全文检索法。全文检索法将非结构化数据中的一部分信息提取出来进行组织,形成索引,然后根据索引快速定位到要查找的信息。Lucene可以实现全文检索的功能,它是Apache软件基金会支持和提供的工具包。 使用Lucene实现全文检索的流程如下: 1. 创建索引:首先获取要进行检索的文档,可以是磁盘文件或网站资源等,然后构建文档对象,包括多个域,如文件名称、文件路径、文件大小、文件内容等。接下来对文档进行分词,将分词结果创建为索引并添加到索引库中。 2. 索引搜索:创建查询对象,执行查询并渲染结果。在倒排索引词典表中查找对应搜索词的索引,然后找到索引所链接的文档。例如,搜索语法为"fileName:lucene"表示搜索文件名中包含Lucene的文档。 要使用Lucene实现全文检索,首先需要下载和配置Lucene。你可以从官方网站或其他可信的资源下载Lucene的安装包,并按照相应的指南进行配置。然后,你可以使用Lucene提供的API来实现全文检索功能,根据具体需求进行代码编写和调用。 总之,Lucene是一种强大的全文检索工具,可以帮助你在MySQL数据表中实现全文检索功能。你可以通过学习和使用Lucene的API来了解更多关于Lucene的功能和用法,并根据具体需求进行相应的实现。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* [【springboot微服务】Lucence实现Mysql全文检索](https://blog.csdn.net/zhangcongyi420/article/details/129940816)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] - *3* [【Lucene&Solr】Lucene实现全文检索](https://blog.csdn.net/qq_43705275/article/details/107229299)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值