Lucene的基本概念----转载yufenfei的文章

Lucene的基本概念

Lucene是什么?

Lucene是一款高性能、可扩展的信息检索工具库。信息检索是指文档搜索、文档内信息搜索或者文档相关的元数据搜索等操作。

信息检索流程如下:

1、 将即将检索的资源集合放到本地,并使用某种特定的结构存储,称为索引,这个索引的集合称为索引库。由于索引库的结构按照专门为快速查询设计的,所以查询的速度非常的快;

2、 搜索操作时都是在本地的索引库中进行查找;

所以对于全文检索功能的开发,要做两方面:索引库管理(维护索引库中的数据)、在索引库中进行搜索。而Lucene就是操作索引库的工具;

索引库是什么样子?

索引库是一个目录,里面是一些二级制文件,就如同数据库,所有的数据也是以文件的形式存放在文件系统中的。我们不能直接操作这些二级制文件,而是使用Lucene提供的API完成相应的操作,就像数据库使用SQL语句一样。

对索引库的操作可以分为两种:管理与查询。

1、 管理索引库使用的IndexWriter;

2、从索引库中查询使用IndexSearcher。

Lucene的数据结构为 Document与Field。

Document代表是一条数据,Field代表数据中的一个属性。一个Document中有多个Field,Field的值为String型,因为Lucene只处理文本;

我们只需要把我们的程序中的对象转换为Doucemnt,就可以交给Lucene管理了,搜索的结果中的数据列表也是Document的集合;

OK,我们来做一个实例,还原一下整个流程

1、创建一个用户类,用于实例化用户数据

Java代码

  1. public class User {
  2. private Long id;
  3. private String name;
  4. private int age;
  5. private String sex;
  6. private Date birthday;
  7. public User(Long id, String name, int age, String sex, Date birthday) {
  8. super();
  9. this.id = id;
  10. this.name = name;
  11. this.age = age;
  12. this.sex = sex;
  13. this.birthday = birthday;
  14. }
  15. //get/set方法,这里省略
  16. }
public class User {

	private Long id;
	private String name;
	private int age;
	private String sex;
	private Date birthday;
	public User(Long id, String name, int age, String sex, Date birthday) {
		super();
		this.id = id;
		this.name = name;
		this.age = age;
		this.sex = sex;
		this.birthday = birthday;
	}
   //get/set方法,这里省略
}

2、生成即将检索的资源数据

Java代码

  1. public class DataUtil {
  2. /**
  3. * 检索资源数据的准备;
  4. *   这里的数据可以来源数据库、文件系统等
  5. * @return
  6. */
  7. public static List<User> getUsers(){
  8. List<User> list =new ArrayList<User>();
  9. User user =new User(1L,"张三1",20,"man",new Date());
  10. list.add(user);
  11. user =new User(2L,"张三2",20,"man",new Date());
  12. list.add(user);
  13. user =new User(3L,"张三3",20,"woman",new Date());
  14. list.add(user);
  15. user =new User(4L,"张三4",20,"man",new Date());
  16. list.add(user);
  17. user =new User(5L,"张三5",20,"man",new Date());
  18. list.add(user);
  19. user =new User(6L,"张三6",20,"woman",new Date());
  20. list.add(user);
  21. return list;
  22. }
  23. }
public class DataUtil {
	/**
	 * 检索资源数据的准备;
	 *   这里的数据可以来源数据库、文件系统等
	 * @return
	 */
	public static List<User> getUsers(){
		List<User> list =new ArrayList<User>();
		User user =new User(1L,"张三1",20,"man",new Date());
		list.add(user);
		user =new User(2L,"张三2",20,"man",new Date());
		list.add(user);
		user =new User(3L,"张三3",20,"woman",new Date());
		list.add(user);
		user =new User(4L,"张三4",20,"man",new Date());
		list.add(user);
		user =new User(5L,"张三5",20,"man",new Date());
		list.add(user);
		user =new User(6L,"张三6",20,"woman",new Date());
		list.add(user);
		return list;
	}
}

3、Lucene创建索引库及查询

Java代码

  1. public class IndexWriterDemo {
  2. /**
  3. * 将即将检索的资源写入索引库
  4. * @param writer
  5. * @throws Exception
  6. */
  7. public void buildDocs(IndexWriter writer)throws Exception {
  8. writer.deleteAll();//清空索引库里已存在的文档(document)
  9. List<User> list = DataUtil.getUsers();//得到数据资源
  10. System.out.println("buildDocs()->总人数为 :"+list.size());
  11. for(User user :list){
  12. Document doc = new Document();//创建索引库的文档
  13. doc.add(new Field("id",String.valueOf(user.getId()),Store.YES,Index.NO));
  14. doc.add(new Field("name",user.getName(),Store.YES,Index.ANALYZED));
  15. doc.add(new Field("age",String.valueOf(user.getAge()),Store.YES,Index.ANALYZED));
  16. doc.add(new Field("sex",user.getSex(),Store.YES,Index.ANALYZED));
  17. doc.add(new Field("birthday",String.valueOf(user.getBirthday()),Store.YES,Index.ANALYZED));
  18. writer.addDocument(doc);//将文档写入索引库
  19. }
  20. int count =writer.numDocs();
  21. writer.forceMerge(100);//合并索引库文件
  22. writer.close();
  23. System.out.println("buildDocs()->存入索引库的数量:"+count);
  24. }
  25. /**
  26. * 从索引库中搜索你要查询的数据
  27. * @param searcher
  28. * @throws IOException
  29. */
  30. public void searcherDocs(IndexSearcher searcher) throws IOException{
  31. Term term =new Term("sex", "man");//查询条件,意思是我要查找性别为“man”的人
  32. TermQuery query =new TermQuery(term);
  33. TopDocs docs =searcher.search(query, 100);//查找
  34. System.out.println("searcherDoc()->男生人数:"+docs.totalHits);
  35. for(ScoreDoc doc:docs.scoreDocs){//获取查找的文档的属性数据
  36. int docID=doc.doc;
  37. Document document =searcher.doc(docID);
  38. String str="ID:"+document.get("id")+",姓名:"+document.get("name")+",性别:"+document.get("sex");
  39. System.out.println("人员信息:"+str);
  40. }
  41. }
  42. }
public class IndexWriterDemo {
	/**
	 * 将即将检索的资源写入索引库
	 * @param writer
	 * @throws Exception
	 */
	public void buildDocs(IndexWriter writer)throws Exception {
		writer.deleteAll();//清空索引库里已存在的文档(document)
		List<User> list = DataUtil.getUsers();//得到数据资源
		System.out.println("buildDocs()->总人数为 :"+list.size());
		for(User user :list){
			Document doc = new Document();//创建索引库的文档
			doc.add(new Field("id",String.valueOf(user.getId()),Store.YES,Index.NO));
			doc.add(new Field("name",user.getName(),Store.YES,Index.ANALYZED));
			doc.add(new Field("age",String.valueOf(user.getAge()),Store.YES,Index.ANALYZED));
			doc.add(new Field("sex",user.getSex(),Store.YES,Index.ANALYZED));
			doc.add(new Field("birthday",String.valueOf(user.getBirthday()),Store.YES,Index.ANALYZED));
			writer.addDocument(doc);//将文档写入索引库
		}
		int count =writer.numDocs();
		writer.forceMerge(100);//合并索引库文件
		writer.close();
		System.out.println("buildDocs()->存入索引库的数量:"+count);
	}

	/**
	 * 从索引库中搜索你要查询的数据
	 * @param searcher
	 * @throws IOException
	 */
	public void searcherDocs(IndexSearcher searcher) throws IOException{
		Term term =new Term("sex", "man");//查询条件,意思是我要查找性别为“man”的人
		TermQuery query =new TermQuery(term);
		TopDocs docs =searcher.search(query, 100);//查找
		System.out.println("searcherDoc()->男生人数:"+docs.totalHits);
		for(ScoreDoc doc:docs.scoreDocs){//获取查找的文档的属性数据
			int docID=doc.doc;
			Document document =searcher.doc(docID);
			String str="ID:"+document.get("id")+",姓名:"+document.get("name")+",性别:"+document.get("sex");
			System.out.println("人员信息:"+str);
		}
	}
  }

4、测试

Java代码

  1. public class TestIndexWriterRAMDirectory {
  2. private IndexWriter writer=null;
  3. private Directory directory=null;
  4. private IndexReader reader = null;
  5. private IndexSearcher searcher=null;
  6. private IndexWriterDemo demo =new IndexWriterDemo();
  7. @Before
  8. public void setUp() throws Exception {
  9. directory = new RAMDirectory();
  10. IndexWriterConfig config = new IndexWriterConfig(Version.LUCENE_36,new SimpleAnalyzer(Version.LUCENE_36));
  11. writer = new IndexWriter(directory,config);
  12. }
  13. @Test
  14. public void testAddDoc()throws Exception {
  15. /**生成索引库*/
  16. demo.buildDocs(writer);
  17. /**查询数据*/
  18. reader = IndexReader.open(directory);
  19. searcher =new IndexSearcher(reader);
  20. demo.searcherDocs(searcher);
  21. }
  22. }
public class TestIndexWriterRAMDirectory {
	private IndexWriter writer=null;
	private Directory directory=null;
	private IndexReader reader = null;
	private IndexSearcher searcher=null;
	private IndexWriterDemo demo =new IndexWriterDemo();

	@Before
	public void setUp() throws Exception {
		directory = new RAMDirectory();
		IndexWriterConfig config = new IndexWriterConfig(Version.LUCENE_36,new SimpleAnalyzer(Version.LUCENE_36));
		writer = new IndexWriter(directory,config);
	}

	@Test
	public void testAddDoc()throws Exception {
		/**生成索引库*/
		demo.buildDocs(writer);

		/**查询数据*/
		reader = IndexReader.open(directory);
		searcher =new IndexSearcher(reader);
		demo.searcherDocs(searcher);
	}
}

测试结果

Java代码

  1. buildDocs()->总人数为 :6
  2. buildDocs()->存入索引库的数量:6
  3. searcherDoc()->男生人数:4
  4. 人员信息:ID:1,姓名:张三1,性别:man
  5. 人员信息:ID:2,姓名:张三2,性别:man
  6. 人员信息:ID:4,姓名:张三4,性别:man
  7. 人员信息:ID:5,姓名:张三5,性别:man
buildDocs()->总人数为 :6
buildDocs()->存入索引库的数量:6
searcherDoc()->男生人数:4
人员信息:ID:1,姓名:张三1,性别:man
人员信息:ID:2,姓名:张三2,性别:man
人员信息:ID:4,姓名:张三4,性别:man
人员信息:ID:5,姓名:张三5,性别:man

OK,代码完毕

实例的Lucene版本为:lucene-3.6.1

在这再次说下Lucene检索的整个流程(请参考demo的代码)

1、建立索引的执行过程 

在建立索引时,先要把文档存到索引库中,还要更新词汇表。

操作步骤如下:

(1)、把数据对象转换成相应的Document,其中的属性转为Field;

(2)、调用工具IndexWriter的addDocument(doc),把Document添加到索引库中;

(3)、Lucene做的操作:

把文档存到索引库中,并自动指定一个内部编号,用来唯一标识这个条数据;内部编号类似与这条数据的地址,在索引库内部的数据进行调整后,这个编号就可能会改变,同时词汇表中的引用的编号也会做相应的改变,以保 证正确。

更新词汇表。把文本中的词找出来放到词汇表中,简历与文档的对应关系。要把那些词放到词汇表中呢?这就用到一个叫Analyzer(分词器)的工具。他的作用是把一段文本中的词按照规则取出所包含的所有词。对应的是Analyzer类,这是一个抽象类,切分词的具体规则是由其子类实现。

在把对象的属性转化为 Field时,相关代码为:

doc.add(new Field(“title”,article.getTitle(), Store.YES, Index.Analyzed))

其中第三个参数的意思为

Store.NO 不存储属性的值;

Store.YES 存储属性的值

第四个参数

Index.NO 不建立索引

Index.ANALYZED 分词后建立索引

Index.NOT_ANALYZED 不分词,把整个内容作为一个词建立索引

Store是影响搜索出的结构是否有指定属性的原始内容。

Index是影响是否可以从这个属性中查询,或者是查询时可以查其中的某些词,还是要把整个内容作为一个词进行查询。

2、从索引库中搜索的执行过程(QueryParse、TopDocs、ScoreDoc)

在进行搜索时,先在词汇表中查找,得到符合条件的文档编号列表。再根据文档编号真正的取数据(Document)

操作步骤如下:

(1)、把要查询字符串转为Query对象。这就像在Hiberante总是用HQL查询时,也要先调用Session.createQuery(hql)转成Hibernate的Query对象一样。把查询字符串转换成Query是使用QueryParser,或者使用MultiFieldQueryParser。查询字符串也要先经过Analyzer(分词器)。要求检索时使用Analyzer要与监理索引使用的Analzyer要一致,否则可能搜索不出正确的结果。

(2)、调用IndexSearcher.search(),进行查询,得到结果。此方法返回未TopDocs,是包含结果的多个信息的一个对象。其中有totalHits代表记录数,ScoreDoc的数组。ScoreDoc是代表一个结果的相关度得分与文档编号等信息的对象。

(3)、取出要用到的数据列表。调用IndexSearcher.doc(scoreDoc.doc)以取出指定编号对应的Document数据,在分页时要用到:一次只取一页的数据。

lucene.rar

原文地址:https://www.cnblogs.com/tangzeqi/p/8458261.html

时间: 2024-08-29 21:10:54

Lucene的基本概念----转载yufenfei的文章的相关文章

云计算的基本概念(转载)

一.云计算的基本概念 "云"这个词已经被说得烂到不能再烂了.云计算,云平台,云+端,云服务,云……但与很多行业里的朋友聊天发现,其实大家对云计算到底是怎么个玩意,并不是太了解.作者今天为大家梳理一下,各种各样的“云”,葫芦里都在卖什么药. 云是网络.互联网的一种比喻说法,计算可以理解为计算机,因此云计算的基本模型,就是远程计算服务:用户通过网络连接到计算机上,获取计算服务.而远程计算机,因为规模效应,可以提供比个人计算机强大若干个数量级的计算能力,可以根据用户需求提可供弹性伸缩的计算资

浅析Windows安全相关的一些概念(转载)

Session 我们平常所说的Session是指一次终端登录, 这里的终端登录是指要有自己的显示器和鼠标键盘等, 它包括本地登录和远程登录.在XP时代每次终端登录才会创建一个Session,但是在Vista后所有的服务程序都运行在Session 0, 其他终端会依次运行在session 1, session 2... Logon Session 登录Session是指不同帐号的登录,它包括System登录, 网络登录及活动交互登录等. 我们在任务管理器里可以看到各种进程运行在不同的帐号下,比如S

非常直白的 js 闭包概念.&lt;转载&gt;

(转载:http://www.felixwoo.com/archives/247) 一.什么是闭包? 官方"的解释是:闭包是一个拥有许多变量和绑定了这些变量的环境的表达式(通常是一个函数),因而这些变量也是该表达式的一部分.相信很少有人能直接看懂这句话,因为他描述的太学术.其实这句话通俗的来说就是:JavaScript中所有的function都是一个闭包.不过一般来说,嵌套的function所产生的闭包更为强大,也是大部分时候我们所谓的"闭包".看下面这段代码: functi

浅析Oracle范式的概念(转载)

范式:英文名称是 Normal Form,它是英国人 E.F.Codd(关系数据库的老祖宗)在上个世纪70年代提出关系数据库模型后总结出来的,范式是关系数据库理论的基础,也是我们在设计数据库结构过程中所要遵循的规则和指导方法.目前有迹可寻的共有8种范式,依次是:1NF,2NF,3NF,BCNF,4NF,5NF,DKNF,6NF.通常所用到的只是前三个范式,即:第一范式(1NF),第二范式(2NF),第三范式(3NF). 下面就简单介绍下这三个范式. ◆ 第一范式(1NF):强调的是列的原子性,即

javascript 中caller,callee,call,apply 的概念[转载]

在提到上述的概念之前,首先想说说javascript中函数的隐含参数:arguments Arguments : 该对象代表正在执行的函数和调用它的函数的参数. [function.]arguments[n] 参数function :选项.当前正在执行的 Function 对象的名字. n :选项, 要传递给 Function 对象的从0开始的参数值索引. 说明Arguments :是进行函数调用时,除了指定的参数外,还另外创建的一个隐藏对象.Arguments是一个类似数组但不是数组的对象,说

转载一篇文章

转载自星巴克        选址于搜索优化有异曲同工之妙 公司楼下竟然没有星巴克,你想过为什么吗? 编者按:本文来自微信公众号「DT 财经(id:DTcaijing)」,编译:唐也钦:36 氪经授权发布. 据说星巴克周边的房子会更贵,这是什么选址大法 当肯德基.麦当劳都在出售中国业务时,星巴克却在今年 7 月豪掷 13 亿元美金,收回了华东市场合资企业剩余的一半股份,实现对中国大陆全部 2800 家店的直营.这还不够,还计划在未来 5 年平均每年新增 400 多家门店. 听说星巴克要积极扩张,包

ASP.NET 2.0服务器控件开发的基本概念(转载)

利用ASP.NET 2.0技术,创建Web自定义服务器控件并不是一件轻松的事情.因为,这需要开发人员了解并能够灵活应用多种Web开发技术,例如,CSS样式表.客户端 脚本语言..NET开发语言.服务器控件开发技术,甚至是当前最火的AJAX技术等等.虽然现实如此"艰难",但是这种开发技术也不是真的难到不可掌握. 事事都要从头做起.本文将针对利用asp.net 2.0技术,创建Web自定义服务器控件的基础知识进行详细介绍,内容包括:服务器控件概念.控件类型.生命周期等. 1.ASP.NET

性能基本概念转载

socket API 如果熟悉linux socket编程的同学阅读完了第一章, 一定有一种说不上来的别扭感觉.因为通常情况下, 当我们讨论socket的时候, 我们一般指的是操作系统提供的网络编程接口里的那个socket概念. 而在ZMQ中, 只是借用了这个概念的名字, 在ZMQ中, 我们讨论到socket的时候, 一般指代的是调用zmq_socket()接口返回的那个socket, 具体一点: zmq socket. zmq socket比起linux socket来说, 逻辑理解起来比较类

Maven学习总结(四)——Maven核心概念--转载

一.Maven坐标 1.1.什么是坐标? 在平面几何中坐标(x,y)可以标识平面中唯一的一点. 1.2.Maven坐标主要组成 groupId:组织标识(包名) artifactId:项目名称 version:项目的当前版本 packaging:项目的打包方式,最为常见的jar和war两种 样例: 1.3.Maven为什么使用坐标? Maven世界拥有大量构建,我们需要找一个用来唯一标识一个构建的统一规范. 拥有了统一规范,就可以把查找工作交给机器. 二.依赖管理 2.1.依赖配置 依赖配置主要