Lucence.net索引技术 一

1、建立索引

为了对文档进行索引,Lucene 提供了五个基础的类,他们分别是 Document, Field, IndexWriter, Analyzer, Directory。下面我们分别介绍一下这五个类的用途:

Document

Document 是用来描述文档的,这里的文档可以指一个 HTML 页面,一封电子邮件,或者是一个文本文件。一个 Document 对象由多个 Field 对象组成的。可以把一个 Document 对象想象成数据库中的一个记录,而每个 Field 对象就是记录的一个字段。

Field

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

Analyzer

在一个文档被索引之前,首先需要对文档内容进行分词处理,这部分工作就是由 Analyzer 来做的。Analyzer 类是一个抽象类,它有多个实现。针对不同的语言和应用需要选择适合的 Analyzer。Analyzer 把分词后的内容交给 IndexWriter 来建立索引。

IndexWriter

IndexWriter 是 Lucene 用来创建索引的一个核心的类,他的作用是把一个个的 Document 对象加到索引中来。

Directory

这个类代表了 Lucene 的索引的存储的位置,这是一个抽象类,它目前有两个实现,第一个是 FSDirectory,它表示一个存储在文件系统中的索引的位置。第二个是 RAMDirectory,它表示一个存储在内存当中的索引的位置。

熟悉了建立索引所需要的这些类后,我们就开始对某个目录下面的文本文件建立索引了,清单1给出了对某个目录下的文本文件建立索引的源代码。

清单 1. 对文本文件建立索引

package TestLucene;

import java.io.File;

import java.io.FileReader;

import java.io.Reader;

import java.util.Date;

import org.apache.lucene.analysis.Analyzer;

import org.apache.lucene.analysis.standard.StandardAnalyzer;

import org.apache.lucene.document.Document;

import org.apache.lucene.document.Field;

import org.apache.lucene.index.IndexWriter;

/**

* This class demonstrate the process of creating index with Lucene

* for text files

*/

public class TxtFileIndexer {

public static void main(String[] args) throws Exception{

//indexDir is the directory that hosts Lucene‘s index files

File   indexDir = new File("D://luceneIndex");

//dataDir is the directory that hosts the text files that to be indexed

File   dataDir  = new File("D://luceneData");

Analyzer luceneAnalyzer = new StandardAnalyzer();

File[] dataFiles  = dataDir.listFiles();

IndexWriter indexWriter = new IndexWriter(indexDir,luceneAnalyzer,true);

long startTime = new Date().getTime();

for(int i = 0; i < dataFiles.length; i++){

if(dataFiles[i].isFile() && dataFiles[i].getName().endsWith(".txt")){

System.out.println("Indexing file " + dataFiles[i].getCanonicalPath());

Document document = new Document();

Reader txtReader = new FileReader(dataFiles[i]);

document.add(Field.Text("path",dataFiles[i].getCanonicalPath()));

document.add(Field.Text("contents",txtReader));

indexWriter.addDocument(document);

}

}

indexWriter.optimize();

indexWriter.close();

long endTime = new Date().getTime();

System.out.println("It takes " + (endTime - startTime)

+ " milliseconds to create index for the files in directory "

+ dataDir.getPath());

}

}

在清单1中,我们注意到类 IndexWriter 的构造函数需要三个参数,第一个参数指定了所创建的索引要存放的位置,他可以是一个 File 对象,也可以是一个 FSDirectory 对象或者 RAMDirectory 对象。第二个参数指定了 Analyzer 类的一个实现,也就是指定这个索引是用哪个分词器对文挡内容进行分词。第三个参数是一个布尔型的变量,如果为 true 的话就代表创建一个新的索引,为 false 的话就代表在原来索引的基础上进行操作。接着程序遍历了目录下面的所有文本文档,并为每一个文本文档创建了一个 Document 对象。然后把文本文档的两个属性:路径和内容加入到了两个 Field 对象中,接着在把这两个 Field 对象加入到 Document 对象中,最后把这个文档用 IndexWriter 类的 add 方法加入到索引中去。这样我们便完成了索引的创建。接下来我们进入在建立好的索引上进行搜索的部分。

2、搜索文档

利用Lucene进行搜索就像建立索引一样也是非常方便的。在上面一部分中,我们已经为一个目录下的文本文档建立好了索引,现在我们就要在这个索引上进行搜索以找到包含某个关键词或短语的文档。Lucene提供了几个基础的类来完成这个过程,它们分别是呢IndexSearcher, Term, Query, TermQuery, Hits. 下面我们分别介绍这几个类的功能。

Query

这是一个抽象类,他有多个实现,比如TermQuery, BooleanQuery, PrefixQuery. 这个类的目的是把用户输入的查询字符串封装成Lucene能够识别的Query。

Term

Term是搜索的基本单位,一个Term对象有两个String类型的域组成。生成一个Term对象可以有如下一条语句来完成:Term term = new Term(“fieldName”,”queryWord”); 其中第一个参数代表了要在文档的哪一个Field上进行查找,第二个参数代表了要查询的关键词。

TermQuery

TermQuery是抽象类Query的一个子类,它同时也是Lucene支持的最为基本的一个查询类。生成一个TermQuery对象由如下语句完成:

TermQuery termQuery = new TermQuery(new Term(“fieldName”,”queryWord”));

它的构造函数只接受一个参数,那就是一个Term对象。

IndexSearcher

IndexSearcher是用来在建立好的索引上进行搜索的。它只能以只读的方式打开一个索引,所以可以有多个IndexSearcher的实例在一个索引上进行操作。

Hits

Hits是用来保存搜索的结果的。

介绍完这些搜索所必须的类之后,我们就开始在之前所建立的索引上进行搜索了,清单2给出了完成搜索功能所需要的代码。

清单2 :在建立好的索引上进行搜索

package TestLucene;

import java.io.File;

import org.apache.lucene.document.Document;

import org.apache.lucene.index.Term;

import org.apache.lucene.search.Hits;

import org.apache.lucene.search.IndexSearcher;

import org.apache.lucene.search.TermQuery;

import org.apache.lucene.store.FSDirectory;

/**

* This class is used to demonstrate the

* process of searching on an existing

* Lucene index

*

*/

public class TxtFileSearcher {

public static void main(String[] args) throws Exception{

String queryStr = "lucene";

//This is the directory that hosts the Lucene index

File indexDir = new File("D://luceneIndex");

FSDirectory directory = FSDirectory.getDirectory(indexDir,false);

IndexSearcher searcher = new IndexSearcher(directory);

if(!indexDir.exists()){

System.out.println("The Lucene index is not exist");

return;

}

Term term = new Term("contents",queryStr.toLowerCase());

TermQuery luceneQuery = new TermQuery(term);

Hits hits = searcher.search(luceneQuery);

for(int i = 0; i < hits.length(); i++){

Document document = hits.doc(i);

System.out.println("File: " + document.get("path"));

}

}

}

在清单2中,类IndexSearcher的构造函数接受一个类型为Directory的对象,Directory是一个抽象类,它目前有两个子类:FSDirctory和RAMDirectory. 我们的程序中传入了一个FSDirctory对象作为其参数,代表了一个存储在磁盘上的索引的位置。构造函数执行完成后,代表了这个IndexSearcher以只读的方式打开了一个索引。然后我们程序构造了一个Term对象,通过这个Term对象,我们指定了要在文档的内容中搜索包含关键词”lucene”的文档。接着利用这个Term对象构造出TermQuery对象并把这个TermQuery对象传入到IndexSearcher的search方法中进行查询,返回的结果保存在Hits对象中。最后我们用了一个循环语句把搜索到的文档的路径都打印了出来。

好了,我们的搜索应用程序已经开发完毕,怎么样,利用Lucene开发搜索应用程序是不是很简单。

  • IndexSearcher——该对象内包含了很多search方法的重载,搜素一个索引,主要就是使用该对象的实例。
  • Query——该类是一个抽象类,其派生类产生的对象,是对各种形式搜索的封装。
    • TermQuery——匹配那些包含单个查询词语(term)的文档。可以使用BooleanQuery进行组合。
    • BooleanQuery——匹配由其他查询(TermQuery或PhraseQuery或者BooleanQuery)布尔组合后形成的查询的文档。
    • FuzzyQuery——模糊查询。
    • RangeQuery——范围查询。
    • 还有很多……
  • QueryParser——将人类语言翻译成上述某种Query对象。
  • TopDocs——搜索结果的容器。TopFieldDocs是其派生类,也是存放搜索结果的容器。

Lucene是允许对索引的并发操作的,具体操作时,要遵循三条简单而严格的规则:

  • 任意数量只读操作可以并行。
  • 对于一个处于写状态的索引来说,也允许任意只读操作并行。
  • 索引的写操作不可以并行,只能有一个实例线程修改索引。

Lucene的并发规则非常简单,而且,这样的规则基本符合我们的直觉思维,因而非常容易记忆。事实上,Lucene并不强制遵守这些规则,但是违背规则,将带来不可预测的风险,例如索引损坏。

实际操作中,一个好的做法是对于执行写操作的对象,使其单一实例化,也就是使用Singleton设计模式。Lucene的索引操作对象,都被设计为线程安全的形式,多个线程可以直接调用,而不需要额外的同步操作。这一点相当体贴。

实际上,可能没有人会故意去不遵守Lucene的并发规则,造成这样的状况,往往是意外,所以,Lucene提供了一套锁,来保护索引。

Lucene的锁以文件的形式保存在磁盘上,一共有两种锁,一种是write.lock,另一种是commit.lock。

要完成最基本的搜索过程,Lucene需要以下几个对象的合作:

  • IndexSearcher——这个对象主要用来检索IndexWriter生成的索引文件,所以IndexSearcher构造的时候,使用一个包含了索引所在目录的Directory对象来构造。IndexSearcher提供的是一种对索引文件的只读访问,里面提供了多种搜索方法。在我第一次的笔记里代码中用到的search方法,接受一个Query对象和一个HitCollector对象,返回值为空。搜索结果被填充到 HitCollector中。
  • Term——该对象是一个和Field相似的对象,包含一个名字和值对。但是目前,在代码里还没有遇到过这个对象,虽然书里提到在建立索引和搜索的过程中都会用到这个东西,但是实际上,我并没有看到。
  • Query——Query类是一个抽象类,在Lucene的内部有许多的实现,虽然说,书中也提到了最基本的Query是TermQuery,但是看了看内部的代码,在笔记1中提到的代码内部,实际上用到是BooleanQuery,而不是TermQuery。
  • TermQuery——最基本的Query,上面也提到了,用来匹配文档中包含的特定的域的特定的值,暂时也没有碰到过。
  • Hits——这个对象本来应该是一个简单的容器,用来包含搜索得到的排序结果的,但是实际上,在笔记1中的代码里,已经看不到这个东西了,Lucene已经不推荐使用这个东西,现在用到的东西是HitCollector似乎是一个更高级的容器了,在代码中我们看到,我们从这个对象中去除了一个Document的数组,包含的元素正是搜索结果。
  • QueryParser——这个对象在书中没有提到,实际上,我觉得必须要有的,本质上就是把一个字符串转换成一个Query对象,实际上,这个东西应该是设计得非常的复杂的,因为搜索引擎一般都提供了很丰富的搜索语法,Lucene也是一样的。构造QueryParser的时候,还可以指定专门的Analyzer。

使用Lucene建立索引,有三个主要步骤。

提取文本。Lucene只能对纯文本建立索引,所以,任何需要建立索引的资料,都要进行过滤处理,从中提取到纯文本。比如对于Word和PDF,我们都要使用相关API将其中的纯文本提取出来,而对于XML和HTML,则意味着要过滤掉所有的tag。

文本分析。要建立索引,首先要将文本分解成一个个片段,一般就是单词,当然也可能是词组,句子等。分割好的东西,可能还要进行归一化处理,以确保最大程度上的检索能力,比如,全部变成小写字母,以后搜索的时候,就能忽略大小写。这个过程对于字母文字,有个步骤,就是回归原型,像英文、德文、法文这些我稍微有点了解的语言里,一般都有“数”,“格”,“态”的变化,而同一个词的变化形式,应该被视为是一个词,而不是不同的词。对于汉语这样的没有变形的语言,这方面就非常方便了,但是汉语却有着另一个不方便的地方,就是汉语的最小单位不是字,而是词。也即汉语需要进行分词处理。英文单词使用空格分隔,分词要简单得多得多。除却这些步骤,还有一个共同的步骤就是删除stop words,简单说就是无意义词,一般来说就是数词,量词,助词,介词,代词等等虚词。

将索引写入磁盘。Lucene将分析好的文本使用一种叫做倒排索引的数据结构写入到磁盘中。倒排索引(inverted index)的建立,完全是为了搜索的方便。如果说,“正排索引”可以回答你一个问题,“这个文档中,包含了哪些关键词?”,那么“倒排索引”回答了你一个相反的问题,就是“哪些文档,包含了关键词X?”。倒排索引是当今所有主流搜索引擎的核心结构,而这些搜索引擎之所以不同,是因为在建立倒排索引时所附加的独特的参数,比如著名的Google PageRank。这些参数决定了最终搜索结果的排序。

要完成最基本的建立索引的过程,Lucene需要以下几个对象的合作:

  • IndexWriter——Lucene内部用来创建索引的最重要的组件。可以创建新索引,或者从文档增量地创建索引。
  • Directory——Directory是一个抽象类,用于表达索引存放的目录,在lucene内部提供了两个实现,一个是FSDirectory,一个是RAMDirectory,顾名思义了。Directory可能在内部提供了锁的机制,使得建立索引和搜索可以同时进行。
  • Analyzer——又是一个抽象类,是IndexWriter的构成组件之一,主要用来分析文本,包括分词,去除stop words等等功能。在构建一个项目的时候,选取或者创建正确的分析器是至关重要的。
  • Document——是Lucene处理的对象,一个Document是一组Field的集合
  • Field——Lucene建立的索引中,每个Document都包含一个或者多个命名的域,被包装在Field类中,Field有多种的类型,Keyword,UnIndexed,Unstored,Text

按照书中的说法,在进行一个最简单的建立索引的过程时候,必须要用到这几个类,但是上一次的笔记中,我也帖了我敲的代码,貌似则个 Directory是没有直接在Indexer的代码中提到的,不过,我进IndexWriter的构造函数看了一下,其实是用到的,如果我们在构造一个 IndexWriter的时候,没有传递一个Directory给它,而是只传了一个路径,那么会默认使用FSDirectory对像的,这是一种使用了简单锁机制的Directory对象。

来源:http://blog.csdn.net/liuzhenwen/article/details/4463261

时间: 2024-11-08 00:17:25

Lucence.net索引技术 一的相关文章

Lucence.net索引技术 二

一. Lucene索引创建和优化 [版本2.9.0以上] Lucene索引的创建首先需要取得几个必须的对象: 1.分词器//可以采用其他的中文分词器 StandardAnalyzer analyzer = new StandardAnalyzer(Version.LUCENE_CURRENT);//分词器 2.lucene目录 File dir = new File(indexDir);// indexDir为文件路径 //这种目录存在锁机制,在打开目录时,写的权利一次只分给一个用户:有效保证了

内存数据库中的索引技术

引言 传统的数据库管理系统把所有数据都放在磁盘上进行管理,所以称作磁盘数据库(DRDB: Disk-Resident Database).磁盘数据库需要频繁地访问磁盘来进行数据的操作,磁盘的读写速度远远小于CPU处理数据的速度,所以磁盘数据库的瓶颈出现在磁盘读写上. 基于此,内存数据库的概念被提出来了.内存数据库(MMDB:Main Memory Database,也叫主存数据库)[1],就是将数据全部或者大部分放在内存中进行操作的数据库管理系统,对查询处理.并发控制与恢复的算法和数据结构进行重

应用索引技术优化SQL 语句一

一.前言 很多数据库系统性能不理想是因为系统没有经过整体优化,存在大量性能低下的SQL 语句.这类SQL语句性能不好的首要原因是缺乏高效的索引.没有索引除了导致语句本身运行速度慢外,更是导致大量的磁盘读写操作,使得整个系统性能都受之影响而变差.解决这类系统的首要办法是优化这些没有索引或索引不够好的SQL语句. 本文讨论和索引相关的有关内容,以及通过分析语句的执行计划来讲述如何应用索引技术来优化SQL 语句.通过分析执行计划,读者可以检查索引是否有用,以及如何创建高效的索引.本文对数据库管理人员以

[论文]内存数据库中的索引技术

原创性申明 本文地址http://blog.csdn.net/zhujunxxxxx/article/details/42490335 转载请注明出处 引言 传统的数据库管理系统把所有数据都放在磁盘上进行管理,所以称作磁盘数据库(DRDB: Disk-Resident Database).磁盘数据库需要频繁地访问磁盘来进行数据的操作,磁盘的读写速度远远小于CPU处理数据的速度,所以磁盘数据库的瓶颈出现在磁盘读写上. 基于此,内存数据库的概念被提出来了.内存数据库(MMDB:Main Memory

Oracle索引技术研究

Oracle索引类型 B树索引 特定类型索引 确定索引列 主键和唯一键值列的索引 外键索引 其他合适的索引列 B树索引 B树索引算法 B树是指B-tree(Balanced Tree),B树的存在是为了存储设备而设计的一种多分叉的树.B树中 每个节点至多含有m个子节点 每个非叶子节点除了根节点之外至少含有⌈m/2⌉个子节点 根节点至少含有2个子节点否则它是叶子节点 有k个子节点的非叶子节点包含k-1个键值 所有叶子节点出现在同一层 其中,m称为该B树的阶,一个3阶B树的节点的排列如同 [指针]键

以骆驼祥子为例研究2018年数据库与索引技术的变化[图]

我们都知道,骆驼祥子是老舍的一部优秀的长篇小说,在初中阶段我们都学习过吧,那么今天, 我就以骆驼祥子为例,来分析一下2018年在建站的过程中,对于数据库和索引技术方面,百度和谷歌等搜索巨头有哪些变化,以此来帮助我们更好的优化数据库结构,少走一些弯路. 博客程序我是接触的比较早的,可能是因为我是小白,在技术方面没有什么强项,因此在建站的过程中,我一般都采用博客程序,当然了,你可以选择ZLBOG或者wordpress都可以,这两款程序系统是我比较喜欢用的,不过我不喜欢用PHP建站,因为技术方面存在一

双索引技术

双索引技术(Two Pointer) 滑动窗口:这两个索引表示的是一个窗口,让这个窗口不停的在数组中滑动,来找到问题的解. -什么叫子数组:可以不连续.但是本题强调了是要连续的.. 解法一:滑动窗口 时间复杂度:O(n),空间复杂度O(1) 因为没有另外开辟空间. class Solution { public: int minSubArrayLen(int s, vector<int>& nums) { //初始化,希望区间不包含任何元素 int l = 0, r = -1; //n

快速掌握数据库索引技术[数据库设计]

索引的分类: 普通索引.主键索引.唯一索引.全文索引.复合(组合)索引. 何时创建索引: (1) 较频繁的作为查询条件的字段; (2) 唯一性太差的字段(如性别/状态字段等),即使我们频繁作为查询的条件,匀不适合创建索引; (3) 数据更新非常频繁的字段(如统计平台当前的在线人数字段/商品的销售数量字段等)是不适合创建索引.  3. 创建索引(也可用可视化工具直接创建,这里我们用代码演示): (1) 普通索引: create index 索引名 on 表名(表字段) (2) 主键索引: 在创建表

数据库索引技术

技术原理 索引是对数据库表中一个或多个列(例如,employee 表的姓名 (name) 列)的值进行排序的结构.如果想按特定职员的姓来查找他或她,则与在表中搜索所有的行相比,索引有助于更快地获取信息. 例如这样一个查询:select * from table1 where id=10000.如果没有索引,必须遍历整个表,直到ID等于10000的这一行被找到为止:有了索引之后(必须是在ID这一列上建立的索引),即可在索引中查找.由于索引是经过某种算法优化过的,因而查找次数要少的多.可见,索引是用