29

Lucene是可以做到的,利用lucene的Filter,具体可以查看lucene的api中的org.apache.lucene.search.CachingWrapperFilter,它可以缓存上次的搜索结果,从而实现在结果中的搜索。

测试实例:
package com.wsjava;
import java.io.IOException;
import org.apache.lucene.analysis.SimpleAnalyzer;
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.CachingWrapperFilter;
import org.apache.lucene.search.Filter;
import org.apache.lucene.search.Hits;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.QueryFilter;

public class IndexTest {

        /**
         * @param args
         * @throws ParseException
         * @throws IOException
         */
        public static void main(String[] args) throws IOException, ParseException {
                index();
                search(“day”); //简单搜索
                searchInResult(“day”, “you”); //在结果集中搜索
        }
        
        public static void index() throws IOException {
                IndexWriter writer = new IndexWriter(“d:/tesindex”,new SimpleAnalyzer(), true);
                writer.setMaxMergeDocs(1000);
                writer.setMergeFactor(100);
                for (int i = 0; i < 10; i++) {
                        Document doc = new Document();
                        String content = “How do you do?”;
                        if (i >= 5) {
                                content = “What's a good day. “;
                        }
                        if (i >= 7) {
                                content = “Nice day. Thanks you!”;
                        }
                        doc.add(new Field(“content”, content, Field.Store.YES,Field.Index.TOKENIZED));
                        writer.addDocument(doc);
                }

        }
        
        //简单实现对qw的搜索.
        public static void search(String qw) throws IOException, ParseException {
                QueryParser queryParser = new QueryParser(“content”,new SimpleAnalyzer());
                Query query = queryParser.parse(qw.trim());
                QueryFilter filter = new QueryFilter(query);
                
                search(query, filter);
        }
        
        //在搜索oldqw的结果集中搜索qw.
        public static void searchInResult(String qw, String oldqw) throws ParseException, IOException {                
                QueryParser queryParser = new QueryParser(“content”,new SimpleAnalyzer());
                Query query = queryParser.parse(qw.trim());
                Query oldQuery = queryParser.parse(oldqw.trim());
                QueryFilter oldFilter = new QueryFilter(oldQuery);
                CachingWrapperFilter filter = new CachingWrapperFilter(oldFilter);
                
                search(query, filter);
        }
        
        private static void search(Query query, Filter filter) throws IOException, ParseException {
                IndexSearcher ins = new IndexSearcher(“d:/tesindex”);
                Hits hits = ins.search(query, filter);
                for (int i = 0; i < hits.length(); i++) {
                        Document doc = hits.doc(i);
                        System.out.println(doc.get(“content”));
                }
                System.out.println();
        }
}

上面是简单的测试程序。当然在实际应用中可以做得比较复杂。

作者:jock Tags: ,

02

200W以下的数据量全部加载到内存最简单的方式是修改Lucene(1.9版本)源码 org.apache.lucene.index.IndexReader文件的第127行 将
return open(FSDirectory.getDirectory(path, false), true);
修改为
return open(new RAMDirectory(FSDirectory.getDirectory(path, false)), true);

将133行的
return open(FSDirectory.getDirectory(path, false), true);
修改为
return open(new RAMDirectory( FSDirectory.getDirectory(path, false)), true);
这样就可以在查询的时候将所有索引一次加载到内存,查询响应时间即使是第一次查询,也会小于0.1秒,但仅适用于索引文档数量不超过200W个,并且平均的页面大小不超过10K,文献检索系统 ,这种方式尤其适合。
创建索引的时候也能够使用 RAMDirectory , 比FSDirectory 要快很多 。

令一种方法:

FSDirectory directory = FSDirectory.getDirectory(args[0], false);   1

RAMDirectory directory = new RAMDirectory(args[0]);                 2

用2代替1即可

作者:jock Tags: ,

02

转:http://www.lucene.org.cn/read.php?tid=65
< 搜索引擎的典型周期: 搜集数据->建立索引->应答搜索请求>

无 论有多少精彩的应用, 这个印刷时代就诞生的公式都不会作废, 公式中最关键的成分是 1. 数据, 2.算法. 虽然二者中谁对结果质量更重要依然引起争论, 我的精力并未放在这两者上. 关于spider已有数本出名的专著, 算法原理的本质也早不是秘密, 这是搜索引擎必备的条件, 是基础设备而不是制胜的杀手锏. 面对一个活生生的搜索引擎, 研究这两者就像面对解剖台上的小白鼠, 却放下手术刀去查上课用的内脏图解. 我只注意实现, 实现是商业效率的体现, 这才是真刀真枪狼烟四起的地方.

抛开数据采集, 上边的周期分成两个相(phase), 1. Indexing(建立索引), 2.Searching(搜索). 还有一个现在看来显得古怪的词-检索, 图书馆系统大多用这个词. 中国人的词汇总是显得睿智, “索”本有求取寻找的意思, “索引”原本就是为搜索创造的. 那些题目是”倒排索引原理”大篇幅对索引和模式匹配进行比较的文章, 因此有些让人哭笑不得. 上述的两个phase正是lucene覆盖的范围(Lucene核心不提供crawler), 这两个phase一个用于生成索引(index), 一个用于从index取出数据, 可以看出Lucene的一切行为都和index有关. 幸好Lucene官方指南 Lucene in Action 在附录中用浅显的语言介绍了index的结构, 这让人了解Lucene怎么把一片片文档塞进去, 就像绞肉机把一片片五花肉里脊肉搅成肉酱. 但是有点遗憾的感觉: 搜索过程怎么把index中支离破碎的数据记录(index的结构用法着实很像数据库)恢复成检索结果? 就像主妇们怎么用屠夫的肉酱作出香喷喷的肉丸?

我从Query 的构造开始, 详细检验了Lucene处理Query的过程. 这种努力使我了解到index中的记录(就是数据库中的record概念), 如何在检索过程中起作用. 这是深入把握Lucene实现的基础, 若要对Lucene作基础的调整和改动, 自然缺不了这一步(这是我的动机之一). 这种探索也帮助我了解原始文档资料的各种属性如何决定搜索结果, 进一步的研究可以揭示出文档各属性的重要性以及文档对查询条件的敏感性, 从这里出发可以提炼出更普遍的原理, 再结合通用的Search Engine原理, 把”Search Engine是什么, 长什么样”深深地刻在脑海中. 这对我是一次很好的搜索引擎进阶的途径. 接下来的就是所谓SE优化( Search Engine Optimizing ), 不敢讲这种天怒人怨的话题…
阅读全文 »

作者:jock Tags:

02

PriorityQueue  实现一优先队列框架,实例非常简单,只需实现lessThan(Object a, Object b)方法即可,通过该方法可以控制大优先或小优先。
阅读全文 »

作者:jock Tags: ,

02

HitCollector 的作用很简单,通过collect()方法控制检索返回的结果,下面是lucene自带的一个例子—-使用一个优先队
列,返回指定数目的Top n Doc。
阅读全文 »

作者:jock Tags: ,

02

修改Similarity(相似度计算)

DefaultSimilarity基本上可以满足一般的搜索要求。但是在有些应用中,你可以定制你自己的Similarity来服务你自己的应用需求。例如:有些人认为没有必要让文档短的文章得分更高一点 (参考 a “fair” similarity).

修改Similarity需要同时对索引和搜索都进行修改,必须在搜索或者排序之间修改Similarity。

要定制你自己的Similarity,也就是你不想直接使用DefaultSimilarity,你只要在建立索引的之前调用IndexWriter.setSimilarity,或者在搜索之前调用Searcher.setSimilarity.

你如果想知道,别人都是怎么修改similarity的,你可以参考一下Lucene的邮件列表Overriding Similarity. 总的来说有下面这些修改: 阅读全文 »

作者:jock Tags:

02

1 lucene简介
1.1 什么是lucene
Lucene是一个全文搜索框架,而不是应用产品。因此它并不像www.baidu.com 或者google Desktop那么拿来就能用,它只是提供了一种工具让你能实现这些产品。

1.2 lucene能做什么
要回答这个问题,先要了解lucene的本质。实际上lucene的功能很单一,说到底,就是你给它若干个字符串,然后它为你提供一个全文搜索服务,告诉你你要搜索的关键词出现在哪里。知道了这个本质,你就可以发挥想象做任何符合这个条件的事情了。你可以把站内新闻都索引了,做个资料库;你可以把一个数据库表的若干个字段索引起来,那就不用再担心因为“%like%”而锁表了;你也可以写个自己的搜索引擎……

1.3 你该不该选择lucene
下面给出一些测试数据,如果你觉得可以接受,那么可以选择。
测试一:250万记录,300M左右文本,生成索引380M左右,800线程下平均处理时间300ms。
测试二:37000记录,索引数据库中的两个varchar字段,索引文件2.6M,800线程下平均处理时间1.5ms。

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

2.1写入流程
源字符串首先经过analyzer处理,包括:分词,分成一个个单词;去除stopword(可选)。
将源中需要的信息加入Document的各个Field中,并把需要索引的Field索引起来,把需要存储的Field存储起来。
将索引写入存储器,存储器可以是内存或磁盘。

2.2读出流程
用户提供搜索关键词,经过analyzer处理。
对处理后的关键词搜索索引找出对应的Document。
用户根据需要从找到的Document中提取需要的Field。 阅读全文 »

作者:jock Tags:

10

Manning – Lucene in Action, A Guide to the Java Search Engine.pdf

PDF文件下载

作者:堕落天使 Tags: ,