Lucene全文检索

来源:互联网 发布:硕鼠for mac官网 编辑:程序博客网 时间:2024/06/05 17:40

 搭建lucene的开发环境,要准备lucenejar包,要加入的jar包至少有:

1) lucene-core-3.1.0.jar     (核心包)

2) lucene-analyzers-3.1.0.jar    (分词器)

3) lucene-highlighter-3.1.0.jar    (高亮器)

4) lucene-memory-3.1.0.jar       (高亮器)

今天学了Lucene的全文检索,写下一下笔记以供日后使用

1.1 全文检索的概念

1) 从大量的信息中快速、准确地查找出要的信息

2) 搜索的内容是文本信息(不是多媒体)

3) 搜索的方式:不是根据语句的意思进行处理。如果要搜索的文本为” 2012年的春晚有赵本山吗”,那么含有这些词(2012年、春晚、赵本山)就能搜索出来。每一个词都是关键词。

4) 全面、快速、准确是衡量全文检索系统的关键指标。

5) 概括:

a) 只处理文本

不处理语义


首先1:lucene全文检索是将客户端保存的对象转化成Document对象保存在制定的dir

         所以写一个普通类转化成Document的对象是很重要的

将普通的Article对象转化成Document对象public static Document ArticleToDocument(Article article){                //创建Document对象<span style="font-family:Tahoma;">                        </span>Document document = new Document();<span style="font-family:Tahoma;">                       //因为只能保存String类型 的字符串,所以必须用lucene自带的类型转换器将int类型转化成String类型</span>                String idStr = NumericUtils.longToPrefixCoded(article.getId());               <p>               //Field<span style="font-family:宋体;">相当于</span><span style="font-family:Calibri;">JavaBean</span><span style="font-family:宋体;">的属性</span></p>              //<p>               /*  a) 第一个参数为属性</p><p>                 b) 第二个参数为属性值</p><p align="left">                 c) 第三个参数为是否往索引库里存储</p><p>                 d) 第四个参数为是否更新引索</p><p>                              1) NO   <span style="font-family:微软雅黑;">不进行引索</span></p><p>                              2) ANALYZED  <span style="font-family:微软雅黑;">进行分词引索</span></p><p>                              3) NOT_ANALYZED <span style="font-family:微软雅黑;">进行引索,把整个输入作为一个词对待。*/</span></p>                document.add(new Field("id", idStr, Store.YES, Index.NOT_ANALYZED));document.add(new Field("title", article.getTitle(), Store.YES, Index.ANALYZED));document.add(new Field("content", article.getContent(), Store.YES, Index.ANALYZED));return document;}//将Document对象转成Article对象public static Article DocumentToArticle(Document doc){Article article = new Article();<span style="font-family:Tahoma;">                        //因为article是int类型所以也需要用自带的类型转换类转换成String类型</span>                article.setId(NumericUtils.prefixCodedToLong(doc.get("id")));article.setTitle(doc.get("title"));article.setContent(doc.get("content"));return article;}

那么现在问题来了怎么将一个对象存储到本地硬盘上呢

好了,直接上代码

              public void save(Article article){              IndexWriter indexWriter = null;try {// 配置当小文件的数量达到多少个后就自动合并为一个大文件,默认为10,最小为2.LuceneUtils.getIndexWriter().setMergeFactor(5);                        //<span style="font-family:Tahoma;">获得存储的位置                                     Directory  directory = FSDirectory.open(new File("./directory"));                                     //获得分词器</span><p>                                     //IKAnalyzer.cfg.xml<span style="font-family:微软雅黑;">为</span><span style="font-family:Tahoma;">IKAnalyzer</span><span style="font-family:微软雅黑;">的配置文件,可以添加扩展词典和停止词典,一般放在classes根目录下</span></p>                         Analyzer=analyzer= new IKAnalyzer();                         //获得indexWriter对象indexWriter = <span style="font-family:Tahoma;"></span>new IndexWriter(directory, analyzer, MaxFieldLength.LIMITED);// 把article转为documentDocument doc = ArticleDocumentUtils.ArticleToDocument(article);//将存储到索引中的doc对象得分乘以100(类似百度推广)//doc.setBoost(100);// 添加到索引中indexWriter.addDocument(doc);} catch (Exception e) {throw new RuntimeException(e);} <span style="font-family:Tahoma;">}</span>

1) 在数据库中,数据库中的数据文件存储在磁盘上。索引库也是同样,索引库中的索引数据也在磁盘上存在,我们用Directory这个类来描述。

2) 我们可以通过API来实现对索引库的增、删、改、查的操作。

3) 在数据库中,各种数据形式都可以概括为一种:表。在索引库中,各种数据形式也可以抽象出一种数据格式为Document

4) Document的结构为:Document(List<Field>)

5) Field里存放一个键值对。键值对都为字符串的形式。

6) 对索引库中索引的操作实际上也就是对Document的操作。

我们发现上面的代码中的一些数据在删除修改查询的时候还要用到,所以我们要写一个工具类

public class LuceneUtils {private static Directory directory;private static Analyzer analyzer;private static IndexWriter indexWriter;static{try {directory = FSDirectory.open(new File("./directory"));analyzer= new IKAnalyzer();} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}}}


好了,存储完成了之后应该取出来了,那么怎么样获取存储的数据呢?还是直接上代码

public List<Article> search(String queryString,int first,int max) throws Exception{List<Article> list = new ArrayList<Article>();// 获得indexSearcher对象IndexSearcher indexSearcher = new IndexSearcher(LuceneUtils.getDirectory());// 将搜索条件转化为Query对象QueryParser queryParser = new MultiFieldQueryParser(Version.LUCENE_30,new String[] { "title", "content" }, LuceneUtils.getAnalyzer());Query query = queryParser.parse(queryString);//设置高亮//设置前缀和后缀Formatter formatter = new SimpleHTMLFormatter("<font color='red'>", "</font>");//scorer封装了关键字               Scorer 查询条件Scorer scorer= new QueryScorer(query);//Fragmenter设置文本的长度。默认为100。Fragmenter fragmenter = new SimpleFragmenter(15);//得到高亮器Highlighter highlighter = new Highlighter(formatter, scorer);//设置文本的长度,如果超过长度则显示不出来highlighter.setTextFragmenter(fragmenter);// 查到到前n条中间值TopDocs docs = indexSearcher.search(query,first+max);//总共查到的数据数量int count = docs.totalHits;ScoreDoc[] topDocs = docs.scoreDocs;//得到比较小的数字int min = Math.min(count,first+max);//分页处理for (int x = first; x <min; x++) {ScoreDoc sdoc = topDocs[x];int docId = sdoc.doc;Document document = indexSearcher.doc(docId);Article article = ArticleDocumentUtils.DocumentToArticle(document);/* * 使用高亮器 *//** * 1、分词器 *      查找关键词 * 2、字段 *      在哪个字段上进行高亮 * 3、字段的内容 *      把字段的内容提取出来 */String titleText = highlighter.getBestFragment(LuceneUtils.getAnalyzer(), "title", document.get("title"));String contentText = highlighter.getBestFragment(LuceneUtils.getAnalyzer(), "content", document.get("content"));if(titleText!=null){article.setTitle(titleText);}if(contentText!=null){article.setContent(contentText);}list.add(article);}return list;}
查询肯定不止这一种啊,不然怎么查询所有的索引,所以介绍几种查询方法,由于查询是得到Query对象进行查询,所以不同的查询方法是得到不同的query对象

    1、关键词查询

Term term = new Term("title","lucene");Query query = new TermQuery(term);

 * 2、查询所有文档

Query query = new MatchAllDocsQuery();

 * 3、范围查询

//查询id为5到15的所有对象Query query = NumericRangeQuery.newLongRange("id", 5L, 10L, true, true);//最后的两个布尔类型代表包涵不包含5和10

 * 4、通配符查询

Term term = new Term("title","*.java");Query query = new WildcardQuery(term);

 * 5、短语查询

因为不好用,不建议使用就不写了

 * 6、Boolean查询

                Term term = new Term("title","北京");TermQuery termQuery = new TermQuery(term);Term term2 = new Term("title","美女");TermQuery termQuery2 = new TermQuery(term2);Term term3 = new Term("title","北京美女");TermQuery termQuery3 = new TermQuery(term3);BooleanQuery query = new BooleanQuery();query.add(termQuery,Occur.SHOULD);query.add(termQuery2,Occur.SHOULD);query.add(termQuery3,Occur.SHOULD);

大概分页查找就这么多了,那么还有删除修改呢

public void delete(int id) {IndexWriter indexWriter = null;try {//indexWriter =LuceneUtils.getIndexWriter();// 从索引库中删除field为id的某一个值,<span style="font-family:Tahoma;">记得转换成String类型</span>indexWriter.deleteDocuments(new Term("id", NumericUtils.intToPrefixCoded(id)));} catch (Exception e) {throw new RuntimeException(e);} }

修改某一个id的article

public void modify(Article article) {IndexWriter indexWriter = null;try {//indexWriter =LuceneUtils.getIndexWriter();// 将article对象转化成document对象Document doc = ArticleDocumentUtils.ArticleToDocument(article);// 从索引库中删除field为id的某一个值indexWriter.deleteDocuments(new Term("id", NumericUtils.longToPrefixCoded(article.getId())));// 再添加到索引库中indexWriter.addDocument(doc);} catch (Exception e) {throw new RuntimeException(e);}}

到现在基本的lucene就差不多了,接着介绍一些细节

1,Directory

指向索引库的位置,有两种Directory

1FSDirectory

1) 通过FSDirectory.open(new File("./indexDir"))建立一个indexDir的文件夹,而这个文件夹就是索引库存放的位置。

2) 通过这种方法建立索引库时如果indexDire文件夹不存在,程序将自动创建一个,如果存在就用原来的这个。

3) 通过这个类可以知道所建立的索引库在磁盘上,能永久性的保存数据。这是优点

4) 缺点为因为程序要访问磁盘上的数据,这个操作可能引发大量的IO操作,会降低性能。

2RAMDirectory

1) 通过构造函数的形式Directory ramdirectory = new RAMDirectory(fsdirectory)可以建立RAMDirectory

2) 这种方法建立的索引库会在内存中开辟一定的空间,通过构造函数的形式把fsdirectory移动到内存中。

3) 这种方法索引库中的数据是暂时的,只要内存的数据消失,这个索引库就跟着消失了。

因为程序是在内存中跟索引库交互,所以利用这种方法创建的索引的好处就在效率比较高,访问速度比较快。

2,MaxFieldLength

 

a) 能存储的最大长度

b) 在IndexWriter的构造方法里使用

c) 值为:

        1) LIMITED    限制的最大长度   值为10000

        2) UNLIMITED 没有限制的最大长度(一般不使用)






0 0
原创粉丝点击