`
mengqingyu
  • 浏览: 328954 次
  • 性别: Icon_minigender_1
  • 来自: 天津
社区版块
存档分类
最新评论

Lucene 详解

阅读更多
1.什么是全文检索
        对于搜索,按被搜索的资源类型,分为两种:可以转为文本的、多媒体类型。我们上一节提到的搜索功能都是搜索的可以转为文本的资源(第一种)。注意,百度或谷歌提供的音乐或视频搜索不是多媒体搜索,他们是按文件名搜索。在智能手机上有一款音乐搜索的软件,可以让他听10秒钟的音乐,然后他就能上网找出这段音乐的名称、演奏者等信息。这是多媒体搜索。
        按搜索的方式,上一节提到的搜索功能都是不处理语义,只是找出包含指定词的所有资源(只对词进行匹配)。下图就是显示“中国的首都是哪里”这个搜索要求对应的结果,可以看到,是没有“北京”这个结果的,结果页面都是出现了这些词的网页:
全文检索(Full-Text Retrieval)是指以文本作为检索对象,找出含有指定词汇的文本。全面、准确和快速是衡量全文检索系统的关键指标。
关于全文检索,我们要知道:1,只处理文本。2,不处理语义。3,搜索时英文不区分大小写。4,结果列表有相关度排序。
        在信息检索工具中,全文检索是最具通用性和实用性的。
全文检索不同于数据库的SQL查询。(他们所解决的问题不一样,解决的方案也不一样,所以不应进行对比)。在数据库中的搜索就是使用SQL,如:SELECT * FROM t WHERE content like ‘%ant%’。这样会有如下问题:
1.匹配效果:如搜索ant会搜索出planting。这样就会搜出很多无关的信息。
2.相关度排序:查出的结果没有相关度排序,不知道我想要的结果在哪一页。我们在使用百度搜索时,一般不需要翻页,为什么?因为百度做了相关度排序:为每一条结果打一个分数,这条结果越符合搜索条件,得分就越高,叫做相关度得分,结果列表会按照这个分数由高到低排列,所以第1页的结果就是我们最想要的结果。
3.全文检索的速度大大快于SQL的like搜索的速度。这是因为查询方式不同造成的,以查字典举例:数据库的like就是一页一页的翻,一行一行的找,而全文检索是先查目录,得到结果所在的页码,再直接翻到这一页。

2.使用Lucene的API操作索引库
        索引库是一个目录,里面是一些二进制文件,就如同数据库,所有的数据也是以文件的形式存在文件系统中的。我们不能直接操作这些二进制文件,而是使用Lucene提供的API完成相应的操作,就像操作数据库应使用SQL语句一样。
        对索引库的操作可以分为两种:管理与查询。管理索引库使用IndexWriter,从索引库中查询使用IndexSearcher。Lucene的数据结构为Document与Field。Document代表一条数据,Field代表数据中的一个属性。一个Document中有多个 Field,Field的值为String型,因为Lucene只处理文本。
        我们只需要把在我们的程序中的对象转成Document,就可以交给Lucene管理了,搜索的结果中的数据列表也是Document的集合。
        有了这些概念,可以写HelloWorld了,其他的概念可以在写完HelloWorld后再进行说明。

3.环境
要加入的jar包有:
lucene-core-3.0.1.jar(核心包)
contrib\analyzers\common\lucene-analyzers-3.0.1.jar(分词器)
contrib\highlighter\lucene-highlighter-3.0.1.jar(高亮)
contrib\memory\lucene-memory-3.0.1.jar(高亮)

4.核心类
索引核心类
1、IndexWriter(写索引)
2、Directory(索引存放位置)
3、Analyzer(分析器)
4、document(文档)
5、Field(域)

搜索核心类
1、IndexSearcher(搜索引)
2、Term(搜索功能基本单元)
3、Query(查询)
4、TermQuery(Query 子类 最基本查询类型)
5、TopDocs(指针容器)

IndexWriter
IndexWriter是在索引过程中的中心组件。这个类创建一个新的索引并且添加文档到一个已有的索引中。
它可以对索引进行添、删、更新操作,但是不能读取或搜索。

添加方法
addDocument (Document)加Document使用默认的分词器
addDocument (Document, Analyzer)加入的时候使用指定的分词器

删除方法
deleteDocuments (Term);
deleteDocuments (Term[]);
deleteDocuments (Query);
deleteDocuments (Query[]);
一般最好有个唯一索引,这样才好删,不然的话有可以会一删一大堆
如:writer.deleteDocument(new Term(“ID”, documentID));

更新方法
注意:更新索引也提供两个方法,其实Lucene是没有办法更新的,只有先删除了再更新,
updateDocument (Term, Document);
如:writer.updateDocument(new Term(“ID”, documenteId), newDocument);
updateDocument (Term, Document, Analyzer)

5.实例
import java.io.IOException;
import java.io.InputStreamReader;
import java.sql.*;
import java.util.Date;
import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.analysis.standard.StandardAnalyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.queryParser.ParseException;
import org.apache.lucene.queryParser.QueryParser;
import org.apache.lucene.search.Hits;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.Query;

public class SqlCon {
	public static void main(String[] args) {
		Date date1 = new Date();
		String connectionUrl = "jdbc:sqlserver://localhost:1433;"
				+ "databaseName=pubs;user=sa;password=";
		Connection con = null;
		Statement stmt = null;
		ResultSet rs = null;
		try {
			Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver");
			con = DriverManager.getConnection(connectionUrl);
			String SQL = "SELECT TOP 10 * FROM users";
			stmt = con.createStatement();
			rs = stmt.executeQuery(SQL);
			IndexWriter writer = new IndexWrite("C://index//",
					new StandardAnalyzer(), true);
			while (rs.next()) {
				Document doc = new Document();
				doc.add(new Field("id", rs.getString("id"), Field.Store.YES,
						Field.Index.TOKENIZED));
				doc.add(new Field("name", rs.getString("name"),
						Field.Store.YES, Field.Index.TOKENIZED));
				doc.add(new Field("sex", rs.getString("sex"), Field.Store.YES,
						Field.Index.TOKENIZED));
				doc.add(new Field("age", rs.getString("age"), Field.Store.YES,
						Field.Index.TOKENIZED));
				writer.addDocument(doc);
			}
			writer.close();
			Date date2 = new Date();
			System.out.println("用时" + (date2.getTime() - date1.getTime())
					+ "毫秒索引已建立");
			DoSearch();
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			if (rs != null)
				try {
					rs.close();
				} catch (Exception e) {
				}
			if (stmt != null)
				try {
					stmt.close();
				} catch (Exception e) {
				}
			if (con != null)
				try {
					con.close();
				} catch (Exception e) {
				}
		}

	}

	public static void DoSearch() throws IOException, ParseException {
		IndexSearcher indexSearcher = new IndexSearcher("C://index//");// 和上面的IndexWriter一样是一个工具
		QueryParser queryParser = new QueryParser("name",
				new StandardAnalyzer());
		Query query = queryParser.parse("yxy");// 这个地方Query是抽象类大家也注意一下
		Hits hits = indexSearcher.search(query);
		// Document doc = null;
		System.out.print("正搜索................");
		System.out.println("找到了" + hits.length() + "个结果");
		for (int i = 0; i < hits.length(); i++) {
			Document doc = hits.doc(i);
			System.out.println("内容是:" + doc.get("name"));// 注意这里输出的是什么
		}
	}
}


6.高亮(Highlight)
需要的jar包为:
// 生成高亮器
Formatter formatter = newSimpleHTMLFormatter("<span class='kw'>", "</span>");
Scorer scorer = newQueryScorer(query);
Highlighter highlighter = newHighlighter(formatter, scorer);
highlighter.setTextFragmenter(newSimpleFragmenter(20));
// 使用高亮器:对content属性值进行摘要并高亮
Stringtext = highlighter.getBestFragment(LuceneUtils.getAnalyzer(),"content", doc.get("content"));
// 如果进行高亮的属性值中没有要搜索的关键字,则返回null
if (text != null) {
   doc.getField("content").setValue(text);
}

7.复合查询(多种查询条件的综合查询)
(1)联合两个索引查询,已解决:
IndexSearcher[] searchers = new IndexSearcher[2];  
searchers[0] = new IndexSearcher(m_indexpath); 
searchers[1] = new IndexSearcher(m_outindexpath); 
MultiSearcher multiSearcher = new MultiSearcher(searchers); 

(2)还有个进行多条件搜索 and 与 or 的操作————
用 MultiFieldQueryParser 建议重新封装
MultiFieldQueryParser.Parser(p[],d[],f[],analyer)
  成or 与 and操作合一 或者
BooleanQuery m_BooleanQuery = new BooleanQuery(); 
Query query = QueryParser.Parse(m_SearchText, "INSTRUMENT_NAME", analyzer); 
Query query2 = QueryParser.Parse(m_SearchText2, "INSTRUMENT_NAME2", analyzer); 
m_BooleanQuery.Add(query, true, false); 
m_BooleanQuery.Add(query2, true, false); 
(3)复合查询(多种查询条件的综合查询)
Query query=MultiFieldQueryParser.parse("索引”,new String[] {"title","content"},analyzer); 
Searcher searcher=new IndexSearcher(indexFilePath); 
Hits hits=searcher.search(query); 
for (int i = 0; i < hits.length(); i++)  { 
            System.out.println(hits.doc(i).get("name")); 
} 

8.为查询优化索引(index)
        Indexwriter.optimize()方法可以为查询优化索引(index),之前提到的参数调优是为indexing过程本身优化,而这里是为查询优化,优化主要是减少index文件数,这样让查询的时候少打开文件,优化过程中,lucene会拷贝旧的index再合并,合并完成以后删除旧的index,所以在此期间,磁盘占用增加, IO符合也会增加,在优化完成瞬间,磁盘占用会是优化前的2倍,在optimize过程中可以同时作search。

9.Lucene 的检索结果排序
        Lucene的排序主要是对org.apache.lucene.search.Sort的使用。Sort可以直接根据字段Field生成,也可以根据标准的SortField生成,但是作为Sort的字段,必须符合以下的条件:唯一值以及Indexed。可以对Integers, Floats, Strings三种类型排序。
        对整数型的ID检索结果排序只要进行以下的简单操作:
Sort sort = new Sort("id");
Hits hits = searcher.search(query, sort);
用户还可以根据自己定义更加复杂的排序,详细请参考API。

10.需要注意的问题
(1)IndexWriter在添加新的document后,需要重新建立Index,则需要调用writer.optimize();方法
(2)Lucene没有update索引的方法,需要删除后重新建立,参考remove方法
(3)用IndexReader删除Document后,需要重新用IndexWriter进行整理,否则无法在进行搜索(不知道是不是我设置问题)
(4)Lucene先在内存中进行索引操作,并根据一定的批量进行文件的写入。这个批次的间隔越大,文件的写入次数越少,但占用内存会很多。反之占用内存少,但文件IO操作频繁,索引速度会很慢。在IndexWriter中有一个MERGE_FACTOR参数可以帮助你在构造索引器后根据应用环境的情况充分利用内存减少文件的操作。根据我的使用经验:缺省Indexer是每20条记录索引后写入一次,每将MERGE_FACTOR增加50倍,索引速度可以提高1倍左右。
(5)并发操作Lucene
所有只读操作都可以并发
在index被修改期间,所有只读操作都可以并发
对index修改操作不能并发,一个index只能被一个线程占用
index的优化,合并,添加都是修改操作
(6)Locking机制
lucence内部使用文件来locking,默认的locking文件放在java.io.tmpdir,可以通过-Dorg.apache.lucene.lockDir=xxx指定新的dir,有write.lock commit.lock两个文件,lock文件用来防止并行操作index,如果并行操作, lucene会抛出异常,可以通过设置-DdisableLuceneLocks=true来禁止locking,这样做一般来说很危险,除非你有操作系统或者物理级别的只读保证,比如把index文件刻盘到CDROM上。

参考:http://www.iteye.com/topic/582236
分享到:
评论

相关推荐

    lucene详解.doc

    1. 基于Java的全文索引引擎Lucene简介:关于作者和Lucene的历史 2. 全文检索的实现:Luene全文索引和数据库索引的比较 3. 中文切分词机制简介:基于词库和自动切分词算法的比较 4. 具体的安装和使用简介:系统...

    Lucene开发详解.pdf

    Lucene开发详解.pdf,详细介绍Lucene的开发

    Lucene 常用功能介绍视频详解

    Lucene 常用功能介绍,视频详解,带课程文档Lucene 常用功能介绍

    Lucene 概述视频详解

    Lucene 概述,视频教程详解,带课程章节文档 Lucene 概述

    lucene、lucene.NET详细使用与优化详解

    lucene、lucene.NET详细使用与优化详解lucene、lucene.NET详细使用与优化详解

    Lucene 实时搜索视频详解

    Lucene 实时搜索,视频详解,带课程文档,Lucene 实时搜索

    全文检索(Lucene)详解

    全文检索(Lucene)Lucene的PDF

    lucene评分公式详解

    本文档详细介绍了lucene中的评分公式以及每个部分的作用,以及如何修改评分公式影响打分。

    Hibernate 与 Lucene 的整合框架详解

    Hibernate 与 Lucene 的整合框架

    Lucene3.0之查询类型详解

    Lucene3.0之查询处理(1):原理和查询类型 各种Query对象详解

    Lucene中文分词源码详解

    Lucene,作为一种全文搜索的辅助工具,为我们进行条件搜索,无论是像Google,Baidu之类的搜索引 擎,还是论坛中的搜索功能,还是其它C/S架构的搜索,都带来了极大的便利和比较高的效率。本文主要是利用Lucene对MS Sql...

    lucene搜索引擎配置详解

    lucene搜索引擎配置,从载入文件,建立索引,搜索三步让你知道lucene搜索的核心技术

    详解SpringBoot+Lucene案例介绍

    主要介绍了详解SpringBoot+Lucene案例介绍,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

    Lucene分词与查询详解

    Lucene分词与查询详解。这是一个完整的实例,希望对大家的开发学习有帮助!!!

    Lucene中的FST算法描述

    描述了Lucene中如何使用FST算法构建term的内存索引,使用了很多图,直观的展现了FST图的构建流程,能够对想了解lucene内部实现机制原理的同学有帮助。

    lucene文档笔记详解

    Lucene是apache软件基金会4 jakarta项目组的一个子项目,是一个开放源代码的全文检索引擎工具包,但它不是一个完整的全文检索引擎

    lucene.net 完全入门教程

    lucene.net 完全入门教程,包括 lucene.net 介绍, lucene.net工作模式, lucene.net分词方法和中文分词方法, lucene.net索引的建立详解, lucene.net搜索详解, lucene.net的下载方法, lucene.net搜索结果实现...

    lucene实现全文搜索

    全文检索介绍 索引 分词 Lucene介绍 Lucene应用详解 索引器 检索器 条件查询 实用工具及高亮器 Lucene综合应用——仿搜索引擎

    lucene中的SpanQuery和PhraseQuery详解(有图示)

    本文档详细讲解了各种SpanQuery的用法,以及它跟PhraseQuery的区别

    lucene搜索过程代码详解

    详细分析lucene搜索的实现过程,通过代码解析,会对lucene的搜索实现过程有一个更加深刻的认识

Global site tag (gtag.js) - Google Analytics