Lucene的系统由基础结构封装、索引核心、对外接口三大部分组成,其中直接操作索引文件的索引核心又是系统的重点。

20140109140716

Lucene包结构功能列表

lucene-core-4.x.jar

org.apache.lucene.analysis 语言分析器,主要用于切词,支持中文主要扩展此类
org.apache.lucene.document 索引存储时的文档结构管理,类似于关系数据库的表结构
org.apache.lucene.index 索引管理,包括索引建立,删除
org.apache.lucene.queryparser 查询分析器,实现查询关键字之间的运算,如与、或、非
org.apache.lucene.store 数据存储管理,主要包括底层的一些io操作
org.apache.lucene.search 检索管理,根据查询条件检索到结果
org.apache.lucene.util 一些公用类

Lucene功能强大,但从根本上说,主要包括两块: 一是文本内容经切词后索引入库; 二是根据查询条件返回结果;

image

查询逻辑

1.查询者输入查询条件,条件之间可以通过特定运算符进行运算,比如查询希望查询到与“中国”和“北京”相关的记录,但不希望结果中包括“海淀区中关村”,于是输入条件为“中国+北京-海淀区中关村”;

2.查询条件被传达到查询分析器中,分析器将将对“中国+北京-海淀区中关村”进行分析,首先分析器解析字符串的连接符,即这里的加号和减号,然后对每个词进行切词,一般最小的词元是两个汉字,则中国和北京两个词不必再切分,但对海淀区中关村需要切分,假设根据切词算法,把该词切分为“海淀区”和“中关村”两部分,则最后得到的查询条件可以表示为:“中国” AND “北京” AND NOT(“海淀区” AND “中关村”)。

3.查询器根据这个条件遍历索引树,得到查询结果,并返回结果集,返回的结果集类似于JDBC中的ResultSet。

4.将返回的结果集显示在查询结果页面,当点击某一条内容时,可以链接到原始网页,也可以打开全文检索库中存储的网页内容。

5.这就是查询的逻辑过程,需要说明的是,Lucene默认只支持英文,为了便于说明问题,以上查询过程采用中文举例,事实上,当Lucene被扩充支持中文后就是这么一个查询过程。

入库逻辑

1.入库者定义到库中文档的结构,比如需要把网站内容加载到全文检索库,让用户通过“站内检索”搜索到相关的网页内容。入库文档结构与关系型数据库中的表结构类 似,每个入库的文档由多个字段构成,假设这里需要入库的网站内容包括如下字段:文章标题、作者、发布时间、原文链接、正文内容(一般作为网页快照)。

2.包含N个字段的文档(DOCUMENT)在真正入库前需要经过切词(或分词)索引,切词的规则由语言分析器(ANALYZER)完成。

3.切分后的“单词”被注册到索引树上,供查询时用,另外也需要把其它不需要索引的内容入库,所有这些是文件操作均由STORAGE完成。

4.Lucene的索引树结构非常优秀,是Lucene的一大特色。

理解核心索引类

为了对文档进行索引,Lucene 提供了五个基础的类

public class IndexWriter

–org.apache.lucene.index.IndexWriter

public abstract class Directory

–org.apache.lucene.store.Directory

public abstract class Analyzer

–org.apache.lucene.analysis.Analyzer

public final class Document

–org.apache.lucene.document.Document

public final class Field

–org.apache.lucene.document.Field

IndexWriter

IndexWriter是在索引过程中的中心组件。

IndexWriter这个类创建一个新的索引并且添加文档到一个已有的索引中。你可以把IndexWriter想象成让你可以对索引进行写操作的对象,但是不能让你读取或搜索。

IndexWriter不是唯一的用来修改索引的类

Directory

Directory类代表一个Lucene索引的位置。它是一个抽象类.

其中的两个实现:

◦第一个是 FSDirectory,它表示一个存储在文件系统中的索引的位置。

◦第二个是 RAMDirectory,它表示一个存储在内存当中的索引的位置。

在我们的Indexer示例中,我们使用一个实际文件系统目录的路径传递给IndexWriter的构造函数来获得Directory的一个实例。IndexWriter然后使用Directory的一个具体实现FSDirectory,并在文件系统的一个目录中创建索引。

Analyzer

在一个文档被索引之前,首先需要对文档内容进行分词处理,并且而剔除一些冗余的词句(例如:a,the,they等),这部分工作就是由 Analyzer 来做的。

Analyzer 类是一个抽象类,它有多个实现。

针对不同的语言和应用需要选择适合的 Analyzer。Analyzer 把分词后的内容交给 IndexWriter 来建立索引。

Document

org.apache.lucene.document.Document

Document文档类似数据库中的一条记录,可以由好几个字段(Field)组成,并且字段可以套用不同的类型。

一个Field代表与这个文档相关的元数据。元数据如作者、标题、主题、修改日期等等,分别做为文档的字段索引和存储。

Document的方法:

◦void add(Fieldable field)添加一个字段(Field)到Document中

◦String get(String name)从文档中获得一个字段对应的文本

Field

org.apache.lucene.document.Field

Field 对象是用来描述一个文档的某个属性的,比如一封电子邮件的标题和内容可以用两个 Field 对象分别描述。

静态内部类

Field.Index Deprecated. This is here only to ease transition from the pre-4.0 APIs.

Field.TermVector Deprecated. This is here only to ease transition from the pre-4.0 APIs.

Field.Store 表示Field的存储方式

◦NO 原文不存储在索引文件中,搜索结果命中后,再根据其他附加属性如文件的Path,数据库的主键等,重新连接打开原文,适合原文内容较大的情况。

◦YES 索引文件本来只存储索引数据, 此设计将原文内容直接也存储在索引文件中,如文档的标题。

关于Field的重要说明

org.apache.lucene.document.StringField

◦A field that is indexed but not tokenized: the entire String value is indexed as a single token.

org.apache.lucene.document.TextField

◦A field that is indexed and tokenized, without term vectors. For example this would be used on a ‘body’ field, that contains the bulk of a document’s text.

org.apache.lucene.document.BinaryDocValuesField

◦The values are stored directly with no sharing, which is a good fit when the fields don’t share (many) values, such as a title field. If values may be shared and sorted it’s better to use SortedDocValuesField.

简单demo

public static void main(String[] args) throws Exception {
    //内存索引目录
    Directory dir = new RAMDirectory();
    //若用文件目录
    //Directory dir = FSDirectory.open(new File("path"));
    Analyzer analyzer = new StandardAnalyzer(Version.LUCENE_46);
    IndexWriterConfig config = new IndexWriterConfig(Version.LUCENE_46, analyzer);
    IndexWriter iwriter = new IndexWriter(dir, config);
    Document doc = new Document();
    String title = "标题";
    String content = "被索引的内容,内容";
    doc.add(new Field("title", title, TextField.TYPE_STORED));
    doc.add(new Field("content", content, TextField.TYPE_STORED));
    iwriter.addDocument(doc);
    Document doc1 = new Document();
    String title1 = "标题1";
    String content1 = "被索引的内容,内容";
    doc1.add(new Field("title", title1, TextField.TYPE_STORED));
    doc1.add(new Field("content", content1, TextField.TYPE_STORED));
    iwriter.addDocument(doc1);
    iwriter.close();
    DirectoryReader ireader = DirectoryReader.open(dir);
    IndexSearcher isearcher = new IndexSearcher(ireader);
    QueryParser parser = new QueryParser(Version.LUCENE_46, "content", analyzer);
    Query query = parser.parse("内容");
    ScoreDoc[] hits = isearcher.search(query, null, 1000).scoreDocs;
    System.out.println("查询结果数:" + hits.length);
    for (int i = 0; i < hits.length; i++) {
        Document hitDoc = isearcher.doc(hits[i].doc);
        System.out.println(hits[i] + "搜索的结果title" + hitDoc.get("title"));
    }
    ireader.close();
    dir.close();
}

输出结果:

查询结果数:2 doc=0 score=0.3715843 shardIndex=-1搜索的结果title标题

doc=1 score=0.3715843 shardIndex=-1搜索的结果title标题1

你可能感兴趣的内容
Lucene自定义扩展QueryParser 收藏,3105 浏览
Lucene概述 收藏,5941 浏览
1条评论
qujtuvtojdc 1年前
Не надо наводить панику. На Наркопе всегда было больше свободы, для хакеров в том числе. Сейчас будем затягивать гайки… тоже по всем направлениям. Акки ваши не взломаны. http://simonz1982.blogcindario.com http://simonz1982.blogcindario.com

selfly

交流QQ群:32261424
Owner