lucene 学习笔记 1

1、索引过程中所涉及到的核心类

1)IndexWriter:负责创建新索引或者打开已有索引,以及向索引中添加、删除或更新被索引文档的信息。它提供对索引文件的写入操作,但是不能用于读取或搜索索引。IndexWriter需要开辟一定空间来存储索引,这个功能由Directory完成。

2)Directory:描述lucene索引的存放位置,抽象类,子类负责具体指向索引的存储路径。IndexWriter不能呢个直接索引文本,需要由Analyzer将文本分割成独立的单词才行。

3)Analyzer:文本文件在被索引之前,需要经过Analyzer处理,从索引文本文件中提取词汇单元,并剔除掉剩下的无用信息。需要注意的是,索引内容不是纯文本文件的需要先转换成文本文档。Analyzer是抽象类,有具体的实现类实现不同的提取词汇策略。(选择什么样的Analyzer是程序设计中非常关键的一步。)

4)Document 和 Field:Document(文档)对象代表一些Field(域)的集合。文档的域代表文档或者和文档相关的一些元数据。Lucene只能处理从二进制文档中提取的以Field实例形式出现的文本。在实现时,我们为每一个检索到的文件创建一个Document实例,并向实例中添加各个域,然后将Document对象添加到索引中,从而完成了文档的索引操作。
Document是一Filed对象的容器;
每个Filed都有一个域名和对应的域值;

 

2、索引过程中所涉及到的核心类

1)IndexSearcher:用于搜索由IndexWriter类创建的索引。IndexSearcher类可以看成是一个以只读方式打开索引的类,它利用Directory实例来掌控前期创建的索引,然后才能提供大量的搜索方法。

2)Term:是搜索功能的基本单元,和Field类似,Term包含一对字符串元素,域名和玉文本值。在搜索过程中可以创建Term对象,并和TermQuery对象结合使用。

QueryParser parser = new QueryParser(Version.LUCENE_30, "contents", new StandardAnalyzer(Version.LUCENE_30)); // 4
Query query = parser.parse("patent"); // 4
 == Query query = new TermQuery(new Term("conten", "patent"));
TopDocs hits = is.search(query, 10); // 5

3)Query 和 TermQuery:Query是个抽象类,TermQuery是其具体实现,用来匹配指定域中包含特定项的文档。

4)TopDocs:是一个简单的指针容器,指针一般指向前N个排名的搜索结果,搜索结果即匹配查询条件的文档。

 

3、文档和域:文档是lucene索引和搜索的原子单位。文档为包含一个或多个域的容器,而域则依次包含其真正被搜索的内容。每个域都有一个标识名称,该名称为一个文本值或二进制值。在对原始数据进行索引操作时,首先需将数据转换成lucene所能识别的文档和域。
lucene可以针对域做3种操作:

1)域值可以被索引或不索引。被索引的域值必须是文本格式的(二进制格式的域值只能被存储)。
2)域被索引后,可以选择性地存储项向量,它可以看成是该域的一个小型反向索引集合,通过该向量能够检索该域的所有语汇单元。
3)域值可以被单独存储。

 

4、索引的操作期间,首先是从原始数据中提取文本,并创建对应的Document实例,该实例包含多个Field实例;然后是分析文本,将域文本处理成大量语汇单元;最后是将语汇单元加入到段结构中。综上,lucene索引过程分3步:将原始文档转换成文本、分析文本、将分析好的文本保存到索引中

 

5、倒排索引(lucene将输入数据以这个数据结构进行存储的):倒排索引是根据属性的值来查找记录的,索引表的每一项都包括一个属性值和具有该属性值的各记录的地址。由于不是由记录来确定属性值,而是由属性值来确定记录的位置,故而成为倒排索引。
倒排文件:具有倒排索引的文件就是倒排索引文件,索引对象是文档或文档集合中的单词,用来存储这些单词在一个文档或一组文档中的存储位置。

 

6、删除索引中的文档

deleteDocuments(Term);删除包含项的文档
deleteDocuments(Term[]);删除包含项数组任一元素的文档
deleteDocuments(Query);负责删除匹配查询语句的文档
deleteDocuments(Query[]);负责删除匹配查询语句数组任一元素的文档


7、更新索引中的文档

lucene不能做到部分更新,lucene的更新操作是:删除整个的就文档,然后向索引中添加新文档。这就要求新文档必须包含就文档中的所有域,包括未改变的内容。

updateDocument(Term, Document);首先是删除包含Term变量的所有文档,然后使用writer的默认分析器添加新文档
updateDocument(Term, Document,Analyzer);功能同上,只是这里指定了分析器


8、域(Field)选项:当创建好一个域时,可以通过指定多个域选项来控制Lucene将文档添加进索引后,域的行为。域选项分为几个独立的类别:索引选项、存储选项和项向量使用选项。

1)域索引选项:通过倒排索引来控制文本是否可被搜索。

Index.ANALYZD:使用分析器将域值分解成独立的语汇单元流,并使每个语汇单元能被搜索。
Index.NOT_ANALYZD:对域进行索引,但不对string值进行分析。实际是将域值作为单一语汇单元并使之能被搜索,适用于索引不能被分解的域值。
Index.ANALYZED_NO_NORMS:Index.ANALYZD的变体,它不会在索引中存储norms信息。
Index.NOT_ANALYZD_NO_NORMS:Index.ANALYZED_NO_NORMS的变体,也不存储norms。

norms记录了索引中的index-time boost信息,可以再索引时节省索引空间和减少内存消耗。
Index.NO:使对应的域值不被搜索。

2)域存储选项:确定是否需要存储域的真实值,以便后续搜索时能恢复这个值。

Store.YES:存储域值。该情况下,原始的字符串值全部被保存在索引中,并可以由IndexReader类恢复。但是会消耗掉索引的存储空间。
Store.NO:不存储域值。通常是域值不用恢复为初始格式。

3)域项向量选项:一种介于域索引和域存储的中间结构。

TermVector.YES:为每个文档都存储一个TermVector。
TermVector.NO:不做向量存储
TermVector.WITH_POSITIONS:YES+位置
TermVector.WITH_OFFSETS:YSE+偏移
TermVector.WITH_POSITIONS_OFFSETS:YES+位置+偏移

 

9、域选项组合:下面列出经常使用的域选项组合及其使用范例。
NOT_ANALYZED_NO_NORMS —— YES —— NO:标识符(文件名、主键),电话号码和社会安全号码、URL、姓名、日期和用于排序的文本域
ANALYZED —— YES —— WITH_POSIATION_OFFSETS:文档标题、摘要
ANALYZED —— NO —— WITH_POSIATION_OFFSETS:文档正文
NO —— YES —— NO:文档类型、数据库主键(没有用于搜索)
NOT_ANALYZED —— NO —— NO:隐藏的关键字

 

10、FIeld扩展:filed的域值除了string外,还可以是二进制格式、TOkenStream值(用于对域的预分析)、reader(如果在内存中对整个域值进行保存会导致较大开销或不方便时可使用)
Field(String name, Reader reader, Field.TermVector termVector) 和Field(String name, Reader reader) :

这种情况下,域值是不被存储的(即Store.NO),并且该域会一直用于分析和索引(即Index.ANALYZED)。

Field(String name, byte[] value, Field.Store store) :

可以用来存储二进制域,store参数必须是Store.YES。

 

11、加权基准-norms

在索引期间,文档和文档中的域所有加权被合并成一个单一的浮点数的加权值,这些加权被合并到一处,并被编码成一个单一的字节值,作为域或文档信息的一部分存储起来。而在搜索期间,被搜素域的norms被加载到内存,并被解码还原为浮点数,然后用于计算相关性评分。
norms面临的问题是在搜索期间的高内存用量,所以可以使用Filed.Index中的NO_NORMS索引来不计算norms的值。


12、实现数字索引
这个问题有两个场景:
1)数字嵌入在将要索引的文本中:要想实现这样的数字索引,只要选择一个不丢弃数字的分析器就可以了。如WhitespaceAnalyzer和StandardAnalyzer。
2)只有数字,实现对数字的索引:(由于lucene只处理文本格式的项,所以这类比较特殊)
解决方法可以将数字转化成字符串。
使用NumericField类对数字域的支持,调用setXXXValue方法记录数值,然后将NumericField类加入文档中。
如:doc.add(new NumericField("price").setDoubleValue(19.99));

 

13、QueryParser类
可以解析用户输入的信息。
QueryParse处理的表达式:
1)java  ——> 默认域中包含java项的文档
2)java junit 或 java OR junit ——> 默认域包含java或junit项的文档
3)+java +junit 或 java AND junit ——> 默认域包含java和junit项的文档
4)title:ant ——> title域中包含ant项的文档
5)title:a -subject:b 或 title:a AND NOT subject:b ——> title域中包含a且subject域中不包含b的文档
6)java* ——>默认域中包含java开头的项的文档


14、IndexSearcher 和 IndexReader类
IndexReader完成了打开所有索引文件和提供底层reader API的工作,打开一个IndexReader需要较大的系统开销。
在创建IndexReader时,它会搜索已有的索引快照。如果需要搜索索引中的变更信息,按道理讲是需要打开一个新的reader。但是IndexReader提供了reopen()方法,是一个获取新IndexReader的有效方法,重启能再消耗较少系统资源的情况下使用当前reader来获取索引中所有的变更信息。
IndexReader newReader = reader.reopen();
if(reader != newReader){
    reader.close();
    reader  =  newReader;
    searcher = new IndexSearcher(reader);
}

索引有变更,reopen方法值返回一个新的reader,这时程序必须关闭旧的reader并创建新的IndexSearcher。

15、搜索结果分页
一般用两种方式实现:

1)每次用户换页浏览时都重新进行查询操作;(较优
2)将首次搜索获得的多页搜索结果收集起来并保存在ScoreDocs实例中,并在用户换页浏览时展现结果;
第二种方法需要存储每个用户的当前浏览状态,这个对web程序开销很大,而lucene的快速处理能力使得重新查找会很快。


16、近实时搜索:能够使用一个打开的IndexWriter来快速搜素索引的变更内容,而不必首先关闭writer或向该writer提交。在使用一个长期打开的IndexWriter来完成持续变更时,就要求对应的搜索能够快速反应索引变更。
如果IndexWriter实例与负责搜索的程序处于同一个JVM中,就可以使用近实时搜索功能。
Indexwriter.getReader(),它会将缓存中的所有变更刷新到索引目录中,然后创建一个新的包含这些变更的IndexReader。如果想要通过IndexWriter完成更多变更,可以使用IndexReader的reopen()方法来获取新的reader。reopen()的效率很高,对于索引中为发生变更的部分,新的reader会共享这些部分中打开的文件,并能缓存先前的reader。

17、
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值