花了小半天的时间研究了一下Lucene全文检索引擎的使用,看网上的教程动辄十几章着实吓人,想起来N年前学习JDBC的时候买了巨厚的一本专门描写JDBC的书籍,现在想想做数据库编程就那么个套路,其实是很简单的,这个Lucene应该也是一样的,先入了门再关注各个细节的犄角旮旯。
先看项目中要用Lucene的话需要引入哪些jar包,我是用maven自动下载的,依赖包如下:
<dependency> <groupId>org.apache.lucene</groupId> <artifactId>lucene-core</artifactId> <version>4.8.0</version> </dependency> <dependency> <groupId>org.apache.lucene</groupId> <artifactId>lucene-queryparser</artifactId> <version>4.8.0</version> </dependency> <dependency> <groupId>org.apache.lucene</groupId> <artifactId>lucene-analyzers-common</artifactId> <version>4.8.0</version> </dependency> <dependency> <groupId>org.apache.lucene</groupId> <artifactId>lucene-highlighter</artifactId> <version>4.8.0</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.11</version> </dependency>
注意junit不是必须的,只是便于写单元测试我就没有删除。
如果不会使用maven,也可以去Lucene的官方网站下载完整的压缩包后自己复制jar包使用,我的测试示例代码用到的jar包如下图:
复制需要用的jar包就行,不用乱七八糟啥都复制到项目里面的。
下面是测试代码,我是在c:\txts目录里面放了几个txt文本文件去建立全文索引的,找了几个公司的项目投标方案,主要目的是测试在比较多的文字内容的情况下全文索引的速度及检索正确率。
代码如下:
package com.xxx; import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; import java.io.FilenameFilter; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.StringReader; import java.text.SimpleDateFormat; import java.util.Date; import org.apache.lucene.analysis.Analyzer; import org.apache.lucene.analysis.TokenStream; import org.apache.lucene.document.Document; import org.apache.lucene.document.Field.Store; import org.apache.lucene.document.LongField; import org.apache.lucene.document.StoredField; import org.apache.lucene.document.StringField; import org.apache.lucene.document.TextField; import org.apache.lucene.index.DirectoryReader; import org.apache.lucene.index.IndexReader; import org.apache.lucene.index.IndexWriter; import org.apache.lucene.index.IndexWriterConfig; import org.apache.lucene.queryparser.classic.MultiFieldQueryParser; import org.apache.lucene.queryparser.classic.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.TopScoreDocCollector; import org.apache.lucene.search.highlight.Highlighter; import org.apache.lucene.search.highlight.QueryScorer; import org.apache.lucene.search.highlight.SimpleHTMLFormatter; import org.apache.lucene.store.Directory; import org.apache.lucene.store.SimpleFSDirectory; import org.apache.lucene.util.Version; import org.junit.Test; import org.wltea.analyzer.lucene.IKAnalyzer; public class TestLucene { // 待索引文件存放路径 private static String source_file_path = "c:\\txts"; // 生成的全文索引文件存储路径 private static String indexDir = "c:\\index_dir"; private static SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); // 中文分词器IKAnalyzer,从http://code.google.com/p/ik-analyzer/downloads/list 下载最新源码放入项目中使用 private static Analyzer analyzer = new IKAnalyzer(); public void createIndex() { Directory directory = null; try { // 有文件系统或者内存存储方式,这里使用文件系统存储索引数据 directory = new SimpleFSDirectory(new File(indexDir)); // 生成全文索引的配置对象 IndexWriterConfig config = new IndexWriterConfig(Version.LUCENE_48,analyzer); // 设置生成全文索引的方式为创建或者追加 config.setOpenMode(IndexWriterConfig.OpenMode.CREATE_OR_APPEND); // 创建真正生成全文索引的writer对象 IndexWriter indexWriter = new IndexWriter(directory, config); // 读取待索引文件夹下的所有的.txt文件 File sourceFiles = new File(source_file_path); String txtFiles[] = sourceFiles.list(new FilenameFilter() { @Override public boolean accept(File dir, String name) { if (name.endsWith(".txt")) { // 这里只对.txt文件创建索引 return true; } return false; } }); // 遍历所有txt文件写入全文索引,如果数据来源是数据库则遍历数据库查询结果集即可 for (String txtFile : txtFiles) { String file = source_file_path + File.separator + txtFile; File input_txt_file = new File(file); System.out.println("开始对" + txtFile + "建立索引"); Document doc = new Document(); // 约等于数据库的一行记录 // 以下生成各个字段的数据值 StringField name = new StringField("filename", input_txt_file.getName(), Store.YES); TextField content = new TextField("content", readFileContent( file, "gbk"), Store.YES); StringField path = new StringField("path",input_txt_file.getAbsolutePath(), Store.YES); StoredField date = new StoredField("date", df.format(new Date())); LongField size = new LongField("size", input_txt_file.length(),Store.YES); // 向Document对象中加入各个字段的值 doc.add(name); doc.add(content); doc.add(path); doc.add(date); doc.add(size); // 向IndexWriter中增加新的一行记录 indexWriter.addDocument(doc); // 提交数据内容 indexWriter.commit(); } indexWriter.close(); directory.close(); } catch (Exception e) { e.printStackTrace(); } } public void search() { String queryString = "test"; //查询条件 String query_fields[]=new String[]{"filename","content"};//对哪几个字段进行查询检索 File file_index_dir = new File(indexDir); try { Directory directory = new SimpleFSDirectory(file_index_dir); IndexReader indexReader = DirectoryReader.open(directory); // 创建搜索类 IndexSearcher indexSearcher = new IndexSearcher(indexReader); QueryParser queryParser = new MultiFieldQueryParser(Version.LUCENE_48, query_fields,analyzer); queryParser.setDefaultOperator(QueryParser.OR_OPERATOR);//多个关键字时采取 or 操作 Query query = queryParser.parse(queryString); TopDocs topDocs = indexSearcher.search(query, 10000);//查询前多少条满足条件的数据 System.out.println("一共查到:" + topDocs.totalHits + "记录"); ScoreDoc[] scoreDoc = topDocs.scoreDocs; for (int i = 0; i < scoreDoc.length; i++) { // 内部编号 int doc = scoreDoc[i].doc; System.out.println("内部编号:" + doc); // 根据文档id找到文档 Document mydoc = indexSearcher.doc(doc); System.out.println("文档路径:" + mydoc.get("path")); //读取path字段的值 } } catch (Exception e) { e.printStackTrace(); } } @Test public void searchPage() { int pageIndex=1; int pageSize=1; int start = (pageIndex - 1) * pageSize; String queryString = "test"; //查询条件 String query_fields[]=new String[]{"filename","content"};//对哪几个字段进行查询检索 File file_index_dir = new File(indexDir); try { Directory directory = new SimpleFSDirectory(file_index_dir); IndexReader indexReader = DirectoryReader.open(directory); // 创建搜索类 IndexSearcher indexSearcher = new IndexSearcher(indexReader); QueryParser queryParser = new MultiFieldQueryParser(Version.LUCENE_48, query_fields,analyzer); queryParser.setDefaultOperator(QueryParser.OR_OPERATOR);//多个关键字时采取 or 操作 Query query = queryParser.parse(queryString); int max_result_size = start + pageSize; TopScoreDocCollector topDocs = TopScoreDocCollector.create(max_result_size, false); indexSearcher.search(query, topDocs); int rowCount = topDocs.getTotalHits(); //满足条件的总记录数 int pages = (rowCount - 1) / pageSize + 1; //计算总页数 TopDocs tds = topDocs.topDocs(start, pageSize); ScoreDoc[] scoreDoc = tds.scoreDocs; System.out.println("一共查到:" + topDocs.getTotalHits() + "记录,共"+pages+"页"); // 关键字高亮显示的html标签,需要导入lucene-highlighter-x.x.x.jar SimpleHTMLFormatter simpleHTMLFormatter = new SimpleHTMLFormatter( "<font color='red'>", "</font>"); Highlighter highlighter = new Highlighter(simpleHTMLFormatter,new QueryScorer(query)); for (int i = 0; i < scoreDoc.length; i++) { // 内部编号 int doc_id = scoreDoc[i].doc; System.out.println("内部编号:" + doc_id); // 根据文档id找到文档 Document mydoc = indexSearcher.doc(doc_id); // 内容增加高亮显示 TokenStream tokenStream2 = analyzer.tokenStream("content",new StringReader(mydoc.get("content"))); String content = highlighter.getBestFragment(tokenStream2,mydoc.get("content")); System.out.println("文件名称:"+mydoc.get("filename")+" 高亮内容:" + content); } } catch (Exception e) { e.printStackTrace(); } } public static String readFileContent(String FileName, String charset) { InputStream fis=null; BufferedReader reader=null; StringBuffer result = new StringBuffer(); try { fis=new FileInputStream(FileName); reader = new BufferedReader(new InputStreamReader(fis, charset)); String line = new String(); while ((line = reader.readLine()) != null) { result.append(line); } } catch (Exception e) { e.printStackTrace(); }finally{ if (null!=reader){ try { reader.close(); } catch (IOException e) {} } if (null!=fis){ try { fis.close(); } catch (IOException e) {} } } //System.out.println("内容:" + result.toString()); return result.toString(); } }
里面除了Lucene以外还用到了中文分词器IKAnalyzer,下载网址http://code.google.com/p/ik-analyzer/downloads/list,下载源码包IK Analyzer 2012FF_hf1_source.rar使用,下载后把src里面的文件复制到项目里面就可以了。
记不清是谁说过读书是先读薄再读厚了,使用Lucene的读薄就是先确定索引数据是存到磁盘文件系统还是内存,确定好以后去实例化Directory对象,然后通过配置参数对象去实例化IndexWriter去写待索引文档,对比数据库系统的话,待索引文档对象Document类似于一行记录,上面的示例里面是通过读取硬盘内的文本文件去填充的Document对象,如果要对数据库里面的记录建立全文索引的话,Document的数据来源通过jdbc读取数据库内容即可。
查询更简单了,确定好查询什么内容,确定查哪几个字段就可以了。
相关推荐
2. 代码示例:通过分析提供的"lucene4.8学习资料和案例"压缩包,可以深入了解Lucene的实践操作,如创建索引、执行查询、处理结果等。 3. 在线教程:网络上有许多优秀的Lucene教程,如《Lucene in Action》一书的在线...
《Lucene 4.8 实例解析》 Lucene 是一个高性能、全文本搜索库,由 Apache 软件基金会开发。它提供了完整的搜索功能,...对于开发搜索引擎、内容管理系统或其他需要全文搜索功能的应用,Lucene 是一个值得信赖的选择。
本示例项目"Lucene4.8+IKAnalyzer+SpringMVC4+Jsoup+Quartz"为我们提供了一个强大的智能搜索引擎搭建框架,它整合了多项关键技术,旨在帮助开发者高效地实现网页抓取、内容分析和定时任务等功能。 首先,Lucene是...
在IT领域,搜索引擎的开发与优化是一项关键技术,而Apache Lucene作为一款高性能、全文本搜索库,是许多开发者进行文本检索的首选工具。本文将深入探讨如何使用Lucene5来创建一个基本的索引,帮助初学者入门。 首先...
Lucene.NET是Apache Lucene项目的一个.NET版本,它是一个全文搜索引擎库,提供了强大的搜索功能,支持多种数据源。在C#中,我们可以利用Lucene.NET进行索引构建、查询解析和结果检索,以实现快速准确的文本搜索。 ...
标题中的“lucene全文检索实例二”指的是使用Apache Lucene这一开源全文搜索引擎库进行二次开发的一个具体案例。在这个实例中,开发者将展示如何在含有10万条数据的环境中实现文件的全文检索,并且包括增、删、改、...
Lucene.NET是Apache Lucene的.NET版本,它是一个高性能、全文本搜索库,提供了强大的索引和搜索功能。而盘古分词是针对中文文本处理的优秀分词工具,它能够将中文文本分解成有意义的词语,以便于搜索引擎理解和处理...
2> 全文检索的实现机制 【1】lucene学习笔记的目录如下 1. 概述 3 2. lucene 的包结构 3 3. 索引文件格式 3 4. lucene中主要的类 4 4.1. Document文档类 4 4.1.1. 常用方法 4 4.1.2. 示例 4 4.2. Field字段类 4 ...
Elasticsearch(简称ES)是一个基于Lucene的开源全文搜索引擎,它提供了分布式、实时、可扩展的搜索和分析引擎。ES不仅仅是一个搜索引擎,它更是一个复杂的数据存储和分析平台,广泛应用于日志分析、监控、推荐系统...
3.2.3. 高级用法示例 3.3. 摘要式认证 3.3.1. 简介 3.3.2. 规范(Specifics) 3.3.3. 身份(Identity) 3.4. HTTP 认证适配器 3.4.1. 简介 3.4.2. 设计回顾 3.4.3. 配置选项 3.4.4. Resolvers 3.4.4.1. ...