`
BuN_Ny
  • 浏览: 85216 次
  • 来自: 济南
社区版块
存档分类
最新评论

8) 第二章 索引:基本索引操作

阅读更多

 

    先上示例代码,原意看的就看,不愿意看的先略过,回头再对照着看也行:

 

import java.io.IOException;

import junit.framework.TestCase;

import org.apache.lucene.analysis.WhitespaceAnalyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.Term;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.TermQuery;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.RAMDirectory;

/**
 * 示例代码:
 * Lucene中document的基本操作
 * (新增、删除、更新)
 */
public class IndexingTest extends TestCase {

	protected String[] ids = { "1", "2" };
	protected String[] unindexed = { "Netherlands", "Italy" };
	protected String[] unstored = { 
			"Amsterdam has lots of bridges",
			"Venice has lots of canals" };
	protected String[] text = { "Amsterdam", "Venice" };

	private Directory directory;

	//---------------------------------------------------------------【新增】
	protected void setUp() throws Exception {
		// A setUp()方法会在每一个测试之前运行,它先创建了一个RAMDirectory用来存储索引信息
		directory = new RAMDirectory();
		// B 参见 D#
		IndexWriter writer = getWriter(); 
		
		// C 遍历所有内容,创建Document及Fields并将Document加入索引
		for (int i = 0; i < ids.length; i++) {
			Document doc = new Document();
			doc.add(new Field("id", ids[i], Field.Store.YES,
					Field.Index.NOT_ANALYZED));
			doc.add(new Field("country", unindexed[i], Field.Store.YES,
					Field.Index.NO));
			doc.add(new Field("contents", unstored[i], Field.Store.NO,
					Field.Index.ANALYZED));
			doc.add(new Field("city", text[i], Field.Store.YES,
					Field.Index.ANALYZED));
			writer.addDocument(doc);
		}
		writer.close();
	}

	// D 在RAMDirectory上创建IndexWriter
	private IndexWriter getWriter() throws IOException { 
		return new IndexWriter(directory, new WhitespaceAnalyzer(),
				IndexWriter.MaxFieldLength.UNLIMITED);
	}

	protected int getHitCount(String fieldName, String searchString)
			throws IOException {
		// E 创建Searcher
		IndexSearcher searcher = new IndexSearcher(directory); 
		Term t = new Term(fieldName, searchString);
		// F 创建简单的单一Term的查询
		Query query = new TermQuery(t); 
		// G 获取结果集的数量
		int hitCount = TestUtil.hitCount(searcher, query); 
		searcher.close();
		return hitCount;
	}

	public void testIndexWriter() throws IOException {
		IndexWriter writer = getWriter();
		// H 验证writer中document的数量
		assertEquals(ids.length, writer.numDocs()); 
		writer.close();
	}

	public void testIndexReader() throws IOException {
		IndexReader reader = IndexReader.open(directory);
		// I 验证searcher中document的数量
		assertEquals(ids.length, reader.maxDoc());
		assertEquals(ids.length, reader.numDocs());
		reader.close();
	}
	
	//---------------------------------------------------------------【删除】
	public void testDeleteBeforeIndexMerge() throws IOException {
		IndexWriter writer = getWriter();
		// 1 索引中有2个document
		assertEquals(2, writer.numDocs());
		// 2 删除第一个document
		writer.deleteDocuments(new Term("id", "1"));
		writer.commit();
		// 3 验证索引中包含了删除操作
		assertTrue(writer.hasDeletions()); 
		// 4 一个被索引的document 一个被删除的document
		assertEquals(2, writer.maxDoc());
		// 5 仅有一个被索引的document
		assertEquals(1, writer.numDocs());
		writer.close();
	}

	public void testDeleteAfterIndexMerge() throws IOException {
		IndexWriter writer = getWriter();
		assertEquals(2, writer.numDocs());
		writer.deleteDocuments(new Term("id", "1"));
		// 5 优化压缩索引
		writer.optimize(); 
		writer.commit();
		assertFalse(writer.hasDeletions());
		// 6 合并后仅剩一个被索引的document
		assertEquals(1, writer.maxDoc()); 
		assertEquals(1, writer.numDocs());
		writer.close();
	}
	
	//---------------------------------------------------------------【更新】
	public void testUpdate() throws IOException {
		assertEquals(1, getHitCount("city", "Amsterdam"));
		IndexWriter writer = getWriter();
		
		// 1 创建新的document用来更新, 其city域为Haag
		Document doc = new Document();
		doc.add(new Field("id", "1", Field.Store.YES, Field.Index.NOT_ANALYZED));
		doc.add(new Field("country", "Netherlands", Field.Store.YES, Field.Index.NO));
		doc.add(new Field("contents", "Amsterdam has lots of bridges", Field.Store.NO, Field.Index.ANALYZED));
		doc.add(new Field("city", "Haag", Field.Store.YES, Field.Index.ANALYZED));
		
		// 2 用新创建的document替换之前的
		writer.updateDocument(new Term("id", "1"), doc);
		writer.close();
		// 3 验证原来的document不存在了
		assertEquals(0, getHitCount("city", "Amsterdam"));
		// 4 验证新的document被加入索引中
		assertEquals(1, getHitCount("city", "Haag")); 
	}

}

 

 还需要一个辅助类上面的代码才能够正确运行:

 

import java.io.IOException;

import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.Query;

public class TestUtil {

	public static int hitCount(IndexSearcher searcher, Query query)	throws IOException {
		return searcher.search(query, 1).totalHits;
	}
	
}

 

 

 

1. 新增Document

    新增方法有两个:

addDocument(Document) - 采用默认的分析器(analyzer)添加文档
addDocument(Document, Analyzer) - 采用指定的分析器添加文档

    需要注意的是,搜索阶段所使用的分析器必须与索引阶段使用的一致,才能正确的搜索到相应结果。

    为了简化问题,示例代码中,待索引的内容为String型,而在实际应用中,它们可能来自PDF等,需要先解析哦!

    在我们的例子中,构造IndexWriter共传入了三个参数:第一个参数Directory表示索引存储的位置(这里是内存);第二个参数是索引过程中所使用的分析器;第三个参数 MaxFieldLength.UNLIMITED 示意IndexWriter要索引文档中所有的词元。如果IndexWriter检测到指定的Directory中并没有index文件存在,它会先创建一个,否则,IndexWriter会仅为其增加新的document.

    IndexWriter还有其它许多构造方法,其中一些接受String或File参数以创建FSDirectory, 还有一些允许你指定是想强制性地创建新索引还是覆盖之前的。更高级的构造器,则允许你设计自己的索引删除策略或是提交策略等。

 

2. 删除Document

    删除方法有四个:      

deleteDocuments(Term);
deleteDocuments(Term[]);
deleteDocuments(Query);
deleteDocuments(Query[]);

    从它们的参数中你也许已经猜出个大概。你可以删掉包含了特定Term的文档,或是符合Query查询条件的。通常,为你的document设计一个名为"id"的Field是个不错的办法,这样就你可以为每个document设置唯一的id,然后通过如下方式删除它:

      writer.deleteDocument(new Term("id", documentID));

    同新增方法一样,删除操作不会被立即写入磁盘中,你需要手动调用commit()以提交所有变化或者调用close()关闭writer.

    示例代码中调用的两个方法 maxDoc() 和 numDocs(), 它们的区别在于:

      maxDoc()   会返回索引中的文档(document)总数,包括删除的和未删除的

      numDocs()  仅返回索引中未被删除的文档数

 

3. 更新Document

    更新方法有两个:

updateDocument(Term, Document);
updateDocument(Term, Document, Analyzer);

    很明显它们的区别在于是否指定特定分析器。

    需要指出的是,更新操作实质上仅仅是删除和新增的加合。该操作会先依据指定Term删除相应的document,然后依据第二个参数为索引增加新的document. 遗憾的是,即便你仅修改了document中的某个field,你也需要删除整个document,再为其增加新的document,也就是说,此操作的最小粒度是document而非field.

 

 

 

 

 

 

2
0
分享到:
评论

相关推荐

    数据库应用技术:第08章_索引与视图.ppt

    数据库应用技术:第08章_索引与视图 本章主要讲述数据库应用技术中索引和视图的相关知识点。索引是与表或视图关联的磁盘上结构,索引中的键存储在一个结构中,使 SQL Server 可以快速有效地查找与键值关联的行。 ...

    SQL SERVER 2005练习集2续 第17章索引

    - 过多的索引会降低写操作的性能,因此应该权衡读写操作的需求。 ### 结论 在SQL Server 2005中,熟练掌握索引的创建、管理和优化是提高数据库性能的重要技能。通过合理设计索引结构,可以显著提升查询速度,同时...

    oracle11g

    第二章:SQL的基本函数 第三章:SQL的数据类型 第四章、WHERE子句中常用的运算符 第五章:分组函数 第六章:数据限定和排序 第七章:复杂查询(上):多表连接技术 第八章:复杂查询(下):子查询 第二部分:...

    第A章习题(索引与散列).doc

    如果采用二级索引,第二级索引占用1KB,剩余255KB用于第一级索引,最多可以存放2056320个记录。 4. 变长数据字段的线性索引组织 对于包含变长数据字段的记录,线性索引需要记录关键码、数据起始地址和数据长度。...

    国家开放大学 形考答案 mysql 实验训练4:视图和索引的构建与使用

    实验目的是基于已有的汽车用品网上商城数据库 Shopping,理解视图和索引的概念和作用,练习视图的基本操作,包括视图的建立、视图的查询、视图的更新、视图的删除,体会视图带来的方便;练习索引的创建和删除,对比...

    王道-操作系统-第二章.pdf

    操作系统是计算机系统中最基本的系统软件,它管理和控制计算机硬件资源,提供各种服务和接口,以便于用户使用计算机。操作系统的核心是进程管理、存储管理、文件管理和设备管理四大模块,本文主要讲解操作系统中进程...

    空间数据库与sql第章-索引与数据完整性(共55张PPT).pptx

    空间数据库与SQL第章-索引与数据完整性 本资源主要介绍了空间数据库与SQL中的索引和数据完整性,涵盖了索引的基本概念、类型、创建方法以及数据完整性的重要性。 一、索引的基本概念 索引是根据表中的一列或多列...

    ORACLE+DBA必备技能详解.pdf

    第二章:数据库的创建和管理 第三章:回滚/撤销段.控制文件和重做日志 第四章:表空间 第五章:表 第六章:索引 第七章:视图 第八章:集群 第十章:用户,资源文件,角色喝授权 第十一章:其他管理特性 第十二章:...

    oracle管理应用工具和sql高级应用视频教程详细完整版

    第二章:oracle安装 第三章:SQL基础知识 第四章:使用SELECT语句 第五章:数据的限定与排序 第六章:多表连接技术 第二部分:ORACLE SQL高级应用 第一章:使用子查询 第二章:用户访问控制 第三章:Oracle的事务和...

    C语言程序设计第二章习题参考答案

    在C语言程序设计的学习过程中,第二章通常会涵盖基础语法和基本编程概念。这份"第二章习题参考答案"提供了对这些概念的实践应用解析,旨在帮助学习者巩固理论知识,提升编程技能。以下是根据标题、描述和标签提取的...

    ORACLE教材

    第二章:sql基础 ORACLE数据类型 SQL基本语法 简单查询 SQL函数 多数据表查询 事务控制 第三章:plsql基础 声明及变量 表达式 PL/SQL数据类型 流程控制 异常处理 过程 函数 游标 包 触发器 第...

    MATLAB第二章答案

    1. **MATLAB界面**:第二章可能会介绍MATLAB的工作空间、命令窗口、编辑器和图形窗口等基本元素,以及如何在这些环境中执行命令和编写脚本。 2. **变量与数据类型**:MATLAB中的变量创建、赋值,以及各种数据类型...

    √第二章 操作系统.docx

    根据给定的信息,我们可以归纳总结出以下相关的IT知识点: ### 1. 外设与CPU的数据交换机制 ...虽然题目没有完整给出具体的操作细节,但PV操作的基本原理可以帮助我们理解如何通过信号量来协调进程之间的同步问题。

    MongDB聚合与索引操作

    尝试插入两条具有相同`uno`值的记录,由于唯一索引的存在,第二次插入将失败。 12. **再次清空集合**: ```javascript db.collectionIndex.remove({}); ``` 清除集合中的所有文档。 13. **创建复合索引**:...

    Java程序设计与数据结构第二章习题答案

    9. **IO流**:虽然可能不是第二章的重点,但简单的输入输出操作对于读写文件或控制台交互是必要的。学习如何使用System.out.println()进行打印,以及Scanner类进行用户输入,将有助于完成习题。 10. **编程实践**:...

    MySQL数据库应用实战教程 第7章教案 索引.docx

    通过本章的学习,学生不仅能掌握索引的理论知识,还能通过动手实践提升实际操作能力,同时培养信息搜集和团队协作的技能。在教学过程中,教师应引导学生积极参与,通过实例解析和课堂实训来巩固所学知识,确保他们...

    第二章-操作系统.docx

    - **二级索引**: 使用一个索引块来存储指向一级索引块的指针。 - **三级索引**: 使用一个索引块来存储指向二级索引块的指针。 假设每个数据块大小为4K,索引块同样为4K,那么: - 一级索引最多可以索引1K个数据块,...

    第二章 操作系统1

    - 在二级索引情况下,文件最大长度可以通过计算各级索引所能指向的块数得出,如题目中所述的116281K字节。 5. **分页存储管理**: - **逻辑地址到物理地址的转换**依赖于页表,逻辑地址由页号和页内地址组成。 -...

    MySQL数据库应用实战教程 第7章教案 索引.pdf

    索引的类型涵盖广泛,包括主键索引(不允许重复,且唯一标识一行)、普通索引(无唯一性要求)、唯一索引(不允许重复但允许NULL)、单列索引和联合索引、聚簇索引(数据行和索引存储在一起)和非聚簇索引(索引和...

Global site tag (gtag.js) - Google Analytics