搜索引擎lucene实现--二半吊子的论调之体系结构

时间:2022-08-02 09:00:14

写这个东西就是两个目的,一是让自己头脑清醒,一是让别人把咱的头脑弄清醒。技术这个东西跟本能一个样,只要你愿意用成就本能的方式去学习技术,谁都可以成就自己。

因为咱不是文科出身,工作了六年,也没有那些牛逼人士的韧力和魄力,曾经就想着能多写写技术博客,但总是没有坚持下去(深叹一口气,你可别像我这样。。)。前些日子又看了一下《康熙王朝》(陈道明演的),被里面的一句话(一言之虚,百患丛生; 一事之虚,遗害终生。)给击蒙了,于是重新想着坚持下去。刚好要跟同事分享lucene,那么也就多学,多看,多想,多写了。

OK,言归正传,到底搜索引擎有多神秘?

对我来说,lucene的出现,没有多少影响,因为当初我还在一个小公司里面糊里糊涂地混日子,而虽然听说过这个东西,但没有用过,仅了解了一下。但自从去了那个网络公司之后,要做搜索系统,我就切实地接触到了这个开源神器。至少在一定程度上讲,让我觉得Google,百度不是那么神奇的公司了。因为他们就是用超大规模的爬虫,倒排表,超大规模的缓存和我不知道的超大的things。

小差时刻:作为一个非计算机专业的从业人员,从一定程度上讲,个人表示很惭愧。尽管有编程之热情,但却没有彻底地钻研从业用到的每个组成部分,这实在有点非专业的风格。我想这个浮躁的社会可能会让很多人变成(编程)这样,Matrix造就了我们追求成果不管原理的工作方式。(抱怨一下,但这是自我深深的反省。)

看一段lucene官网的示例代码:

 1 import org.apache.lucene.analysis.Analyzer;
 2 import org.apache.lucene.analysis.standard.StandardAnalyzer;
 3 import org.apache.lucene.document.Document;
 4 import org.apache.lucene.document.Field;
 5 import org.apache.lucene.document.TextField;
 6 import org.apache.lucene.index.DirectoryReader;
 7 import org.apache.lucene.index.IndexWriter;
 8 import org.apache.lucene.index.IndexWriterConfig;
 9 import org.apache.lucene.queryparser.classic.QueryParser;
10 import org.apache.lucene.search.IndexSearcher;
11 import org.apache.lucene.search.Query;
12 import org.apache.lucene.search.ScoreDoc;
13 import org.apache.lucene.store.Directory;
14 import org.apache.lucene.store.RAMDirectory;
15 import org.apache.lucene.util.Version;
16 
17 public final class TestLucene {
18 
19     public static void main(String[] args) throws Exception{
20         Analyzer analyzer = new StandardAnalyzer(Version.LUCENE_CURRENT);
21 
22         // Store the index in memory:
23         Directory directory = new RAMDirectory();
24         // To store an index on disk, use this instead:
25         //Directory directory = FSDirectory.open("/tmp/testindex");
26         IndexWriterConfig config = new IndexWriterConfig(Version.LUCENE_CURRENT, analyzer);
27         IndexWriter iwriter = new IndexWriter(directory, config);
28         Document doc = new Document();
29         String text = "This is the text to be indexed.";
30         doc.add(new Field("fieldname", text, TextField.TYPE_STORED));
31         iwriter.addDocument(doc);
32         iwriter.close();
33         
34         // Now search the index:
35         DirectoryReader ireader = DirectoryReader.open(directory);
36         IndexSearcher isearcher = new IndexSearcher(ireader);
37         // Parse a simple query that searches for "text":
38         QueryParser parser = new QueryParser(Version.LUCENE_CURRENT, "fieldname", analyzer);
39         Query query = parser.parse("text");
40         ScoreDoc[] hits = isearcher.search(query, null, 1000).scoreDocs;
41         // Iterate through the results:
42         for (int i = 0; i < hits.length; i++) {
43           Document hitDoc = isearcher.doc(hits[i].doc);
44           System.out.println(hitDoc.get("fieldname"));
45         }
46         ireader.close();
47         directory.close();
48     }
49     
50 }

声明:以上这段代码,main里面的代码都是取自lucene官网的。但也要特别说明一下,在maven pom.xml里面,对于lucene4.0版本的依赖配置如下:

<dependency>
<groupId>org.apache.lucene</groupId>
<artifactId>lucene-core</artifactId>
<version>4.0.0</version>
</dependency>
<dependency>
<groupId>org.apache.lucene</groupId>
<artifactId>lucene-analyzers-common</artifactId>
<version>4.0.0</version>
</dependency>
<dependency>
<groupId>org.apache.lucene</groupId>
<artifactId>lucene-queryparser</artifactId>
<version>4.0.0</version>
</dependency>

好像3.x版本的不需要这么多配置的吧(好像又好久没跟进lucene测试了。。呵呵)

仅仅从这个demo的import里面,我们能看到lucene的基本功能结构分割:

搜索引擎lucene实现--二半吊子的论调之体系结构

 

Lucene是一个文本内容的全文检索系统,从上图我们也可以看出lucene的确有比较明确且抽象的架构设计。

IndexWriter:接收业务数据,并将索引好的数据写入到Store中。IndexWriter在接收数据时,主要依靠封装了文本内容及其元数据的Document(org.apache.lucene.document,夹缝中引用一下,实在是委屈了Document,它也是具有皇室直系血统的类,非常重要。),它在org.apache.lucene.index包中。index包主要管理索引创建阶段用到的各种类,如IndexReader, IndexWriter....(还有很多底层类,不一一列举,但后面在详细说明时,会一一分析。)

Store:这是一个相对底层的组织,对应包为org.apache.lucene.store,其主要包含与索引数据文件读写管理相关的各种类。

IndexSearcher: 这个是使用Query数据对索引数据进行检索的类。猜得出来,它在org.apache.lucene.search中。

QueryParser:它也是存在于org.apache.lucene.search中,并且其主要职责是解析用户的输入字符串,并返回Query对象,然后供IndexSearcher使用,其对IndexSearcher的重要性跟Docment之于IndexWriter有的一拼。

Analyzer:最后才说到Analyzer,并不是说它不重要,相反它极其重要。Analyzer类主要用户对文本内容进行分词处理,而分词质量的好坏关系到搜索结果的相关度,所以也就有了针对不同文化和语言的各种Analyzer。正如图中展现的,建立和查询索引时都要用到它,是居家旅行的必备良药。

对于网络用户来说,他们只需要关心query data(就是他们想搜的关键词或者句子),经过Parser解析成关键字的query(queryparser的结果),经由IndexSearcher来查询Indexed Data,并返回结果。而我们在对目标数据建索引的过程,则是经由IndexWriter来解析和分解处理,然后将解析的结果(这是个big problem)保存成Indexed Data。

这里要区分一下,网络用户他们只想查找关心的数据,所以他们输入:关键词;而我们开发者则有业务数据。这里就是说,在使用lucene时,是否需要想想以下几个方面:

数据获取:提供用于接收业务数据的接口,搜索请求处理接口;

lucene封装:组装索引Document的接口,返回结果的封装接口,更重要的是log接口(统计和实验);

 

瞻前顾后,咱会从Analyzer,Document,Index,Search and Store几个方面,给各位分享一下lucene的情况。

一点点来,不着急。。。。。