Lucene简单入门

一 .什么是Lucene

lucene是一款高性能的、可扩展,纯java语言编写的信息检索(IR)工具库

它适合几乎任何需要全文本搜索(特别是跨平台)的应用程序

下载地址

 http://lucene.apache.org/java

二 .Lucene的原理

lucene是基于关键词索引和查询

全文分析:把文本解析为一个个关键字存储到索引文件中

倒排索引: (英语:Invertedindex),也常被称为反向索引置入档案反向档案,是一种索引方法,

被用来存储全文搜索下某个单词在一个文档或者一组文档中的存储位置映射。它是文档检索系统中最常用的数据结构

设有两篇文章12
文章1的内容为:

  Tom lives in Guangzhou,I live in Guangzhoutoo.
文章2的内容为:

  He once lived inShanghai.

)全文分析

首先我们要取得这两篇文章的关键词,通常我们需要如下处理措施

 a.我们现在有的是文章内容,即一个字符串,我们先要找出字符串中的所有单词,即分词。英文单词由于用空格分隔,比较好处理。中文单词间是连在一起的需要特殊的分词处理。

 b.文章中的”in”, “once” “too”等词没有什么实际意义,中文中的“的”“是”等字通常也无具体含义,这些不代表概念的词可以过滤掉 。

c.用户通常希望查“He”时能把含“he”,“HE”的文章也找出来,所以所有单词需要统一大小写。

d.用户通常希望查“live”时能把含“lives”,“lived”的文章也找出来,所以需要把“lives”,“lived”还原成“live”

e.文章中的标点符号通常不表示某种概念,也可以过滤掉
 

lucene中以上措施由Analyzer类完成

经过上面处理后

文章1的所有关键词为:

    [tom] [live] [guangzhou] [i] [live] [guangzhou]

文章2的所有关键词为:

    [he] [live] [shanghai]

2) 倒排索引:有了关键词后,我们就可以建立倒排索引了。

上面的对应关系是:“文章号”对“文章中所有关键词”。

倒排索引把这个关系倒过来,变成:“关键词”对“拥有该关键词的所有文章号”。

文章12经过倒排后变成


通常仅知道关键词在哪些文章中出现还不够,我们还需要知道关键词在文章中出现次数和出现的位置,通常有两种位置:

a)字符位置,即记录该词是文章中第几个字符(优点是关键词亮显时定位快);

b)关键词位置,即记录该词是文章中第几个关键词(优点是节约索引空间、词组(phase)查询快),lucene中记录的就是这种位置。

加上“出现频率”和“出现位置”信息后,我们的索引结构变为: 

live 这行为例我们说明一下该结构:live在文章1中出现了2次,文章2中出现了一次,它的出现位置为“2,5,2”这表示什么呢?我们需要结合文章号和出现

频率来分析,文章1中出现了2次,那么“2,5”就表示live在文章1中出现的两个位置,文章2中出现了一次,剩下的“2”就表示live是文章2中第2个关键字

三.简单的Lucene的调用

创建maven项目 ,在pom.xml中配置分词器的架包

<dependencies>
    <!-- 添加一个分词器的jar包 -->
  	<dependency>
	  <groupId>com.janeluo</groupId>
	  <artifactId>ikanalyzer</artifactId>
	  <version>2012_u6</version>
	</dependency>

简单的搜索和创建索引库
package cn.et;  
import java.io.File;  
import java.io.IOException;  
import org.apache.lucene.analysis.Analyzer;  
import org.apache.lucene.document.Document;  
import org.apache.lucene.document.Field;  
import org.apache.lucene.document.TextField;  
import org.apache.lucene.index.DirectoryReader;  
import org.apache.lucene.index.IndexWriter;  
import org.apache.lucene.index.IndexWriterConfig;  
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.store.Directory;  
import org.apache.lucene.store.FSDirectory;  
import org.apache.lucene.util.Version;  
import org.wltea.analyzer.lucene.IKAnalyzer;  
public class IndexDemo {      
    static String drc="E:\\index";  
    //定义存储目录  
    static Analyzer aly= new IKAnalyzer();  
    public static void main(String[] args) throws Exception {  
        search();     
    }  
    //搜索  
    public static void search() throws Exception {  
        Directory dr= FSDirectory.open(new File(drc));  
        //读取存储目录  
        DirectoryReader ird=DirectoryReader.open(dr);  
        //搜索类  
        IndexSearcher isearcher=new IndexSearcher(ird);  
        //Lucene查询解析 用于指定查询的属性名和分词器  
        QueryParser parser = new QueryParser(Version.LUCENE_47,"userDesc", aly);  
        //开始搜索  
        Query query=parser.parse("来");  
        //获取搜索的结果指定返回的docuemnt个数  
        ScoreDoc[] hits= isearcher.search(query, null, 10).scoreDocs;  
        for(int i=0;i<hits.length;i++){  
            //获取单独的document  
            Document hitDoc = isearcher.doc(hits[i].doc);  
            System.out.println(hitDoc.getField("userName").stringValue());  
        }  
            ird.close();  
            dr.close();  
    }  
    //创建索引库  
    public static void write() throws IOException{  
        //索引库的存储目录  
        Directory dr= FSDirectory.open(new File(drc));  
        //管联Lucene版本和当前分词器  
        IndexWriterConfig cfi= new IndexWriterConfig(Version.LUCENE_47,aly);  
        //传入目录和分词器  
        IndexWriter iwriter = new IndexWriter(dr,cfi);  
        //document对象Field属性  
        Document doc= new Document();  
        //TextField.TYPE_STORED 写入存储目录  
        Field field= new Field("userName","张三",TextField.TYPE_STORED);  
         doc.add(field);  
         field= new Field("userDesc","张三来自永州,喜欢吃永州血鸭",TextField.TYPE_STORED);  
         doc.add(field);  
         Document doce= new Document();  
            //TextField.TYPE_STORED 写入存储目录  
            Field field1= new Field("userName","李四",TextField.TYPE_STORED);  
                doce.add(field1);  
             field1= new Field("userDesc","李四来自北京,喜欢吃烤鸭",TextField.TYPE_STORED);  
             doce.add(field1);  
         //写入存储目录  
         iwriter.addDocument(doc);  
         iwriter.addDocument(doce);  
         iwriter.commit();  
         iwriter.close();  
    }  
}  

添加高亮pom.xml依赖

		<!-- 加入高亮的jar包 -->
		<dependency>
		  <groupId>org.apache.lucene</groupId>
		  <artifactId>lucene-highlighter</artifactId>
		  <version>4.7.2</version>
		</dependency>
简单的添加高亮 其他的根上面代码一样

	/**
	 * 搜索
	 */
	@Override
	public List<Map> search(String field, String value) throws Exception{
		Directory directory = FSDirectory.open(new File(dir));
		
		//读取索引库的存储目录
		DirectoryReader ireader = DirectoryReader.open(directory);
		
		//搜索类
		IndexSearcher isearcher = new IndexSearcher(ireader);
		
		//lucence查询解析 用于指定查询的属性名和分词器
		QueryParser parser = new QueryParser(Version.LUCENE_47, field, analyzer);
		
		//开始搜索
		Query query = parser.parse(value);
		
		//最终结果被分词后添加前缀和后缀的处理页<B></B>
		SimpleHTMLFormatter htmlFormatter = new SimpleHTMLFormatter("<font color=red>","</font>");
		
		//将高亮搜索的词 添加到高亮处理器中
		Highlighter highlighter = new Highlighter(htmlFormatter, new QueryScorer(query));
		
		//获取搜索的结果 指定返回的docuemnt个数
		 ScoreDoc[] hits = isearcher.search(query, null, 10).scoreDocs;
		 
		 List<Map> list=new ArrayList<Map>();
	     for (int i = 0; i < hits.length; i++) {
	       int id = hits[i].doc;
	       Document hitDoc = isearcher.doc(hits[i].doc);
	       Map map=new HashMap();
	       map.put("foodid", hitDoc.get("foodid"));
	       String foodname=hitDoc.get("foodname");
	       
	       //将查询的结果和搜索词匹配 匹配到添加前缀和后缀高亮
	       TokenStream tokenStream = TokenSources.getAnyTokenStream(isearcher.getIndexReader(), id, "foodname", analyzer);
	       
	       //传入的第二个参数是查询的值
	       TextFragment[] frag = highlighter.getBestTextFragments(tokenStream, foodname, false, 200);
	       
	       String foodnameHign="";
		   for (int j = 0; j < frag.length; j++) {
			   if ((frag[j] != null) && (frag[j].getScore() > 0)) {
		        	foodnameHign=((frag[j].toString()));
		       }
		   }
	      map.put("foodname",foodnameHign);
	      map.put("price",  hitDoc.get("price"));
	      map.put("imagepath",  hitDoc.get("imagepath"));
	      list.add(map);
	    }
		ireader.close();
		directory.close();
		return list;
	}






评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值