`
cxshun
  • 浏览: 724555 次
  • 性别: Icon_minigender_1
  • 来自: 广州
社区版块
存档分类
最新评论

再入lucene

 
阅读更多

        相信很多人都听过lucene,这样一个用于实现搜索引擎功能的一个工具包。说它是一个工具包,因为它只是提供我们用于索引和查询的工具,并不包含真正一个搜索引擎需要的其他东西——爬虫,抽取等等。

        废话不多说,我们直接来看看lucene4的一些简单的例子(lucene4.1已经出了,暂时没来得及看有什么变化,lucene的API经常修改,所以版本间可能会有些不同的,大家需要注意):

        还是给下lucene的下载地址,有些朋友喜欢用百度的,但那家伙太坑人了,很多外国网站没的。下载地址如下:http://archive.apache.org/dist/lucene/java/4.0.0/

        下载后,我们可以看到有一堆的文件夹,首先demo里面当然就是例子了,这个不多说。看看还是有好处的。

        我们经常使用的无非是下面几个:queryparser,analysis,core(核心,显然是必须的了),queries,其他的貌似比较少用到,除非你进行比较深入的定制,可能会用到suggest(建议方面的东西),其他的因为我暂时没接触到,就不在这里误人子弟了,以后有机会再学习。

        好,接下来来点干货了。我在例子中用到的包有analysis,queryparser,core,另外的暂没有使用。说到底是一个索引工具包,首先当然是建立索引啦,
        比如我现在在ubuntu下,我的eclipse目录是/opt/programs/eclipse,我要索引它里面的所有文件的文件名,放在一个名叫fileName的field里面。

        在看代码前,我们先来了解一下lucene索引的结构:

        一个索引是由无数多个doc组成的,而doc也是由无数多个field组成的。举个比较符合生活的例子:我们可以把一个索引想像成一本书,而doc则是每一本书的第一篇文章,而field则是每一篇文章里面的词语,词组,我们就是通过词组去找到那篇文章。(当然,说根据词组等去找一篇文章不太可行,我们可以把词语换成标题,每一篇文章的标题,这样肯定可以找到对应的文章的。)

        进行lucene检索的情况就是查找field,如果找到对应的,则把该doc取出来,作为我们查询出来的结果。

        1)首先我们看看索引情况:

        

package com.shun.lucene.simple;

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.analysis.standard.StandardAnalyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field;
import org.apache.lucene.document.TextField;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.IndexWriterConfig;
import org.apache.lucene.index.IndexWriterConfig.OpenMode;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.FSDirectory;
import org.apache.lucene.util.Version;

public class IndexAllFiles {

	public static void main(String[] args) {
		Directory dir = null;
		IndexWriter indexWriter = null;
		Analyzer analyzer = new StandardAnalyzer(Version.LUCENE_40);
		try {
			dir = FSDirectory.open(new File("allFiles"));
			
			IndexWriterConfig iwc = new IndexWriterConfig(Version.LUCENE_40,analyzer);
			/*
			 * 如果索引存在的情况下,我们采取什么样的策略
			 * 这里我们使用的是:存在的情况下新增
			 * 不存在的情况下创建
			 * 这符合我们一般的使用规则
			*/
			iwc.setOpenMode(OpenMode.CREATE);
			indexWriter = new IndexWriter(dir,iwc);
			File file = new File("/opt/programs/eclipse");
			System.out.println("Starting analyze fileNames...Please wait...");
			List<String> fileNameList = checkAllFile(file);
			System.out.println("Ending analyze fileNames...");
			for (String fileName:fileNameList) {
				/*
				 * field就是lucene里面的最小单位了,一个索引里面可以有一大堆Document,而一个document里面可以有很多field
				 * 这跟文章类似,一本书里面有很多篇文章,而一篇文章里面可以有很多单词,词组等。
				 */
				Document doc = new Document();
				Field field = new Field("fileName",fileName.toString(),TextField.TYPE_STORED);
				doc.add(field);
				indexWriter.addDocument(doc);
			}
			System.out.println("Writing index to file");
			System.out.println("Finish indexing");
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			try {
				indexWriter.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}
	
	/**
	 * 此方法只是循环列出所传入的文件夹下的所有文件列表
	 * @param dir
	 * @return
	 */
	private static List<String> checkAllFile(File dir) {
		List<String> fileNameList = new ArrayList<String>();
		//不是目录的话里面肯定没文件了,我们在下面直接添加该文件到列表就OK了
		if (dir.isDirectory()) {
			for (File file:dir.listFiles()) {
				//由于我在linux下,并且当前运行eclipse的用户非root,会有权限的问题,所以我这里加了一个判断是否可读
				//正常情况下在windows上不需要,只需要判断是否是目录,然后递归调用即可。
				if(file.isDirectory() && file.canRead()) {
					fileNameList.addAll(checkAllFile(file));
				} else {
					fileNameList.add(file.getName());
				}
			}
		} else {
			fileNameList.add(dir.getName());
		}
		return fileNameList;
	}

}
         相信注释已经够清楚了吧。

 

         这里有个地方需要解释下:

for (String fileName:fileNameList) {
/*
* field就是lucene里面的最小单位了,一个索引里面可以有一大堆Document,而一个document里面可以有很多field
 * 这跟文章类似,一本书里面有很多篇文章,而一篇文章里面可以有很多单词,词组等。
*/
	Document doc = new Document();
	Field field = new Field("fileName",fileName.toString(),TextField.TYPE_STORED);
	doc.add(field);
	indexWriter.addDocument(doc);
}

         我们这里是通过多个doc来添加的,注意,我们频繁的addDocument可能效率不高,我们其实可以把所有的fileName放在一个doc里面,doc并不像我们的map,它不会合并相同的名称的field的。我们稍后来看看这种情况。

         2)有了索引之后,我们肯定就是需要在索引当中找我们需要的东西了。我们搜索一个eclipse这个单词,当然,我们前面只有一个fileName这个field,没有其他的,也只能查那一个了。

package com.shun.lucene.simple;

import java.io.File;
import java.io.IOException;

import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.analysis.standard.StandardAnalyzer;
import org.apache.lucene.index.DirectoryReader;
import org.apache.lucene.queryparser.classic.ParseException;
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.store.Directory;
import org.apache.lucene.store.FSDirectory;
import org.apache.lucene.util.Version;

public class ReadFromIndex {

	public static void main(String[] args) {
		Directory dir = null;
		Analyzer analyzer = new StandardAnalyzer(Version.LUCENE_40);
		try {
			//这里打开的当然就是我们之前建立的索引文件夹了
			dir = FSDirectory.open(new File("allFiles"));
			//DirectoryReader这个是lucene的一个工具类,在以前的IndexSearcher里面,貌似不用使用这个
			IndexSearcher searcher = new IndexSearcher(DirectoryReader.open(dir));
			QueryParser parser = new QueryParser(Version.LUCENE_40,"fileName",analyzer);
			Query query = parser.parse("eclipse");
			TopDocs topDocs = searcher.search(query, 10);
			System.out.println("找到结果数:"+topDocs.totalHits);
			for (ScoreDoc scoreDoc:topDocs.scoreDocs) {
				System.out.println(searcher.doc(scoreDoc.doc).get("fileName"));
			}
		} catch (IOException e) {
			e.printStackTrace();
		} catch (ParseException e) {
			e.printStackTrace();
		}
	}

}

         我们可以看到,查询很简单,只是指定一个索引所在目录,然后来个IndexSearcher,再结合几个QueryParser和Query,然后就搞定了。

         结果就不截图了,大家私下去运行下。我们来看看索引里面的内容,这里又涉及到另外的工具了,luke,这个是用于看索引的工具,可以到这里去下载:http://code.google.com/p/luke/downloads/list。但到了4.0.0alpha就没更新好久了,好在alpha对4.0的正式版还能用。

        我们打开我们的索引,可以看到doc的内容:


         在这里,我们可以看到doc的数量,2835,还有doc里面的field名称和value,另外的IdfXXX和Norm这个大家有兴趣自己可以去研究,是lucene的一些属性信息,包含是否索引、分词等等。

 

        这里,我们是通过多个doc来添加的,我们上面说了,其他我们完全可以把多个field添加到同一个doc里面,虽然同一个fielName,但无所谓,因为索引并不是map形式的,不会覆盖相应的值。

        我们回到上面的创建索引的例子,我们把循环的代码修改如下:

Document doc = new Document();
for (String fileName:fileNameList) {
	/*
	 * field就是lucene里面的最小单位了,一个索引里面可以有一大堆Document,而一个document里面可以有很多field
	* 这跟文章类似,一本书里面有很多篇文章,而一篇文章里面可以有很多单词,词组等。
	 */
Field field = new Field("fileName",fileName.toString(),TextField.TYPE_STORED);
				doc.add(field);
}
indexWriter.addDocument(doc);

         我们把Document提出去了,并且只在最后的时候来一个addDocument,添加到indexWriter中去。这里,我们可以点击luke的File->Re-open current index来重新打开当前的索引。我们可以看到:


         我们可以看到,doc只剩一个了,而里面的fileName却有一大堆了。

         当然,我们在一个doc里面添加了多个同样名字的filedName之后,在检索的时候通过searcher.doc(scoreDoc.doc).get("xxx")这样取出来的只能是第一个了,我们可以换成getValues("xxx")这样就可以取出数组,再进行遍历。

 

 

         说到了索引,当然少不了分词了,中文分词比较好的有,IKAnalyzer,Paoding分词,另外的一些由于没用过不大清楚,大家可以在 网上找找。使用起来都比较简单,这里不说了。我们例子中用到了StandardAnalyzer,这里我们再说一下stopWords这个定义,对于非中文的,分词一般会根据一个stopWords列表来进行分词,比如遇到the,a,an等会自动忽略,并且会把左右的单词分开索引。
        我们可以找到StopAnalyzer这个类,可以看到它定义有一组默认的stopWords。
 final List<String> stopWords = Arrays.asList(
      "a", "an", "and", "are", "as", "at", "be", "but", "by",
      "for", "if", "in", "into", "is", "it",
      "no", "not", "of", "on", "or", "such",
      "that", "the", "their", "then", "there", "these",
      "they", "this", "to", "was", "will", "with"
    );
         中文的当然比这个复杂多了,这个大家可以去看看中文分词的处理,实际上使用的时候只是实例化的时候换一个Analyzer而已,使用很简单。
  • 大小: 37.7 KB
  • 大小: 9.2 KB
  • 大小: 25.2 KB
分享到:

相关推荐

    java Lucene初级教程

     lucene提供的服务实际包含两部分:一入一出。所谓入是写入,即将你提供的源(本质是字符串)写入索引或者将其从索引中删除;所谓出是读出,即向用户提供全文搜索服务,让用户可以通过关键词定位源。 2.1写入流程 ...

    lucene-4.3.1资源

    对于Java开发者来说,这通常可以通过Eclipse、IntelliJ IDEA等IDE工具完成,或者手动将JAR包放入项目的lib目录下,并在构建脚本(如Maven或Gradle)中添加依赖。确保正确导入所有必要的JAR包至关重要,因为Lucene的...

    lucene入门小例子

    Lucene是中国大百科全书式的全文检索库,它在Java世界中扮演着核心角色,为开发者提供了强大的...总之,Lucene是一个强大且灵活的全文检索工具,通过这个入门小例子,你可以逐步揭开其神秘的面纱,踏入文本搜索的世界。

    Lucene 2.0.0下载安装及简单测试

    假设我们创建了名为“luceneDemo”的目录,位于“E:\Lucene”下,并在该目录中放入了一些.txt格式的文档。 接下来,打开命令行界面(DOS),切换到“E:\Lucene”目录下,执行以下命令: ``` java org.apache....

    深入了解Lucene之四 主要算法介绍.ppt

    例如,当合并因子为b时,每当栈顶有b个大小为size的索引时,就将它们合并为一个新索引并推入栈中。这个过程可以直观地分为几个步骤,如添加文档、检查是否需要合并、执行合并等。通过这种方式,Lucene可以有效地管理...

    Lucene.Net.rar 2.0 ver asp.net 组件

    将Lucene.Net组件放入ASP.NET项目的Bin目录下,可以方便地通过引用该DLL来集成全文搜索功能。ASP.NET的事件驱动模型与Lucene.Net的异步处理机制相得益彰,可以实现高效且无阻塞的搜索服务。 总结来说,Lucene.Net ...

    lucene5+zoie实现近实时索引

    开发者可以通过API接口,轻松地将新数据接入到Zoie系统,实现近实时索引。 总结来说,结合Lucene 5的优秀搜索性能和Zoie的实时索引能力,我们可以构建出一个既能处理大规模数据,又能实现实时更新的搜索引擎。这种...

    Lucene 4.8全文检索引擎入门示例文档

    《Lucene 4.8 全文检索引擎入门详解》 Lucene 是一款开源的全文检索库,由 ...通过理解其核心组件和工作流程,以及实践简单的索引创建和查询操作,你就能迈入 Lucene 的世界,进一步探索和应用其高级特性和优化技巧。

    lucene中文分词(庖丁解牛)庖丁分词

    4. 分词处理:在索引文档时,先用庖丁分词器对中文文本进行分词,然后将分词结果转换成Lucene的Term对象,再添加到索引中。 5. 搜索优化:在搜索阶段,同样可以使用庖丁分词器对用户输入的查询进行预处理,提高搜索...

    lucene部署步骤

    - 将下载的Lucene JAR文件放入Tomcat的`lib`目录下。这使得Lucene库对所有部署在Tomcat中的应用都可见。 - 修改`$CATALINA_HOME/conf/server.xml`文件,为你的应用创建一个新的Context,例如: ```xml ...

    IK分词器集成lucene4.5使用方法

    其设计目标是提供一个可以方便地在Lucene、Solr等项目中快速接入的中文分词组件。IKAnalyzer支持热更新词典,能够动态添加或删除词汇,这在处理新词汇或者特殊领域词汇时非常有用。 集成IKAnalyzer到Lucene 4.5的...

    Lucene检索数据库支持中文检索

    - `QueryParser`调用`parser`进行语法分析,形成查询语法树,并放入`Query`对象中。 - `IndexSearcher`调用`search`方法对查询语法树`Query`进行搜索,得到结果`TopScoreDocCollector`。 #### 二、代码示例 ####...

    Lucene5学习之多线程创建索引

    一种常见的多线程策略是使用工作队列(如Java的`ExecutorService`),将待索引的文档放入队列,然后由多个工作线程从队列中取出文档,通过`IndexWriter`进行索引。这种方式可以避免线程间的直接竞争,同时利用多核...

    lucene查询结果集分页代码

    在lucene搜索分页过程中,可以有两种方式 一种是将搜索结果集直接放到session中,但是假如结果集非常大,同时又存在大并发访问的时候,很可能造成服务器的内存不足,而使服务器宕机 还有一种是每次都重新进行搜索,这样...

    lucene分词包

    lucene自带的中文分词器,将jar放入编译路径即可使用

    lucene中文分词器(paoding解牛)

    Paoding这个名字来源于中国古代的一种宰牛技术,寓意其对中文文本的“解构”能力,如同庖丁解牛般精细入微。 Paoding的核心特点包括: 1. **智能词典**:Paoding使用了一种动态加载的词典机制,能够根据上下文信息...

    Lucene使用lucene入门[归类].pdf

    - 将分析后的数据放入Document对象中,每个字段(Field)可以设置存储和索引属性。 - 将Document写入索引存储,存储介质可以是内存或磁盘。 2. **读出流程**: - 用户输入关键词,同样经过Analyzer处理。 - ...

    java大数据内容_7Flume、Kafka、Sqoop、Lucene

    ### Java大数据内容_7Flume、Kafka、Sqoop、Lucene #### 一、Flume 入门 ##### 1.1 Flume 概述 Flume 是一个分布式的、可靠的、高可用的日志采集系统,主要用于收集、汇总和移动大量的日志数据。它由 Cloudera ...

Global site tag (gtag.js) - Google Analytics