`
xusulong
  • 浏览: 80975 次
  • 性别: Icon_minigender_1
  • 来自: 南京
社区版块
存档分类
最新评论

索引 基本索引操作

阅读更多

主要内容为读Lucene in action 所得

基本的索引操作包括:

  1. 向索引添加文档
  2. 删除索引中的文档
  3. 恢复被删除的文档
  4. 更新索引中的文档

下面就这个四个方面分别详述(以测试类来进行示例)

1.向索引添加文档

这个抽象类作为基础,此后2,3,4中都会实现此抽象类,其中setUp函数为JUnit测试时候首先调用的函数,在此函数中做了初始化工作

 

注意 Field的构造函数的不同用法,我根据自己的理解加了注释

 

import java.io.IOException;

import junit.framework.TestCase;

import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.analysis.SimpleAnalyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.FSDirectory;


/**
 * @author xusulong
 *
 */
public abstract class BaseIndexingTestCase extends TestCase {
	protected String[] keywords = {"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"};
	protected Directory dir;
	
	protected void setUp() throws IOException {
		String indexDir = 
			System.getProperty("java.io.tmpdir", "tmp") + 
			System.getProperty("file.separator") + "index-dir";
		dir = FSDirectory.getDirectory(indexDir);
		addDocument(dir);
	}
	
	protected void addDocument(Directory dir) throws IOException{
		IndexWriter writer = new IndexWriter(dir, getAnalyzer(), true, IndexWriter.MaxFieldLength.LIMITED);
		writer.setUseCompoundFile(isCompound());
		
		for(int i = 0; i < keywords.length; i ++) {
			Document doc = new Document();
			//不分析,索引,存储
			doc.add(new Field("id", keywords[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.optimize();
		writer.close();
	}
	/**
	 * 默认分析器
	 * @return
	 */
	protected Analyzer getAnalyzer() {
		return new SimpleAnalyzer();
	}
	
	protected boolean isCompound() {
		return true;
	}
}
 

 

2.删除索引中的文档

文档的删除是通过IndexReader类实现的(从某种程度上说,这个名字显得不太合适,因为没有完全表达出该类真实的功能)。这个类并没有立即从索引中删除文档,而只是在这些文档上加一个删除标记,直到IndexReader调用close()后才真正将它们删除

这个类继承自1.中的BaseIndexTestCase

import java.io.IOException;

import org.apache.lucene.index.IndexReader;
import org.apache.lucene.index.IndexWriter;


/**
 * @author xusulong
 *
 */
public class DocumentDeleteTest extends BaseIndexingTestCase {

	
	public void testDeleteBeforeIndexMerge() throws IOException {
		IndexReader reader = IndexReader.open(dir);
		assertEquals(2, reader.maxDoc());
		assertEquals(2, reader.numDocs());
		reader.deleteDocument(1);
		
		//isDelete(int)用于检查一个特定变化的文档的状态
		assertTrue(reader.isDeleted(1));
		//hasDeletions()用于检查一个所有是否包含了带有删除标记的文档
		assertTrue(reader.hasDeletions());
		assertEquals(2, reader.maxDoc());
		assertEquals(1, reader.numDocs());
		
		reader.close();
		
		reader = IndexReader.open(dir);
		assertEquals(2, reader.maxDoc());
		assertEquals(1, reader.numDeletedDocs());
		
		reader.close();
	}
	
	public void testDeleteAfterIndexMerge() throws IOException {
		IndexReader reader = IndexReader.open(dir);
		assertEquals(2, reader.maxDoc());
		assertEquals(2, reader.numDocs());
		reader.deleteDocument(1);
		reader.close();
		
		IndexWriter writer = new IndexWriter(dir, getAnalyzer(), false, IndexWriter.MaxFieldLength.LIMITED);
		writer.optimize();
		writer.close();
		
		reader = IndexReader.open(dir);
		//删除标记reader close后没有了,所有false
		assertTrue(reader.isDeleted(1));
		assertTrue(reader.hasDeletions());
		assertEquals(1, reader.maxDoc());
		assertEquals(1, reader.numDocs());
		
		reader.close();
		
	}
}

 IndexReader中两个易混淆的方法maxDoc() 和 numDocs()的区别:前者返回下一个 可得到的文档的内部编号,后者返回索引中的文档数量。因为索引仅仅包含两个文档,所以numDocs()返回 2;而文档编号是从0开始的,所以maxDoc()也返回2。

注:每一个Lucene文档都有一个惟一的内部编号。这些编号的分配不是永久的,因为当索引中的段合并时,Lucene会重新分配其编号。因此,你不能认为某一特定的文档会一直拥有某一个固定的内部编号。

 

3.恢复被删除的文档

由于文档的删除是推迟到IndexReader实例关闭的时候才进行的,所以Lucene允许在文档被标记删除但还没有执行最后的删除操作之前,恢复被标 记为删除的文档。可以通过调用undelete()方法移除索引目录中的.del文件来恢复被删除的文件。随后,关闭IndexReader实例,这样就 保留了索引中所有标记为删除的文档。如果用IndexReader实例标记了删除文档,那么只有调用同一个IndexReader实例的 undeleteAll()方法,才能在最初的位置恢复各个被标记为删除的文档(也就是说,IndexReadel实例只能处理自身标记的删除文档,无法 恢复其他实例的文档)。

4.更新索引中的文档

Lucene不提供update(Document)方法。为了达到更新的目的,必须首先从一个索引中删除待更新的文档,然后将修改过的文档重新添加到索引中

import java.io.IOException;

import org.apache.lucene.analysis.Analyzer;
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.ScoreDoc;
import org.apache.lucene.search.TermQuery;
import org.apache.lucene.search.TopDocs;


/**
 * @author xusulong
 *
 */
public class DocumentUpdateTest extends BaseIndexingTestCase {
	public void testUpdate() throws IOException {
		assertEquals(1, getHitCount("city", "Amsterdam"));
		
		IndexReader reader = IndexReader.open(dir);
		//删除在city域中包含Amsterdam的文档
		reader.deleteDocuments(new Term("city", "Amsterdam"));
		reader.close();
		//核实该文档是否被删除
		assertEquals(0, getHitCount("city", "Amsterdam"));
		
		IndexWriter writer = new IndexWriter(dir, getAnalyzer(), false, IndexWriter.MaxFieldLength.LIMITED);
		
		Document doc = new Document();
		//重新添加city域的值为"Haag"的文档
		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));
		writer.addDocument(doc);
		writer.optimize();
		writer.close();
		//确认文档已经更新
		assertEquals(1, getHitCount("city", "Haag"));
	}
	
	protected Analyzer getAnalyzer() {
		return new WhitespaceAnalyzer();
	}
	
	private int getHitCount(String filedName, String searchString) throws IOException{
		IndexSearcher searcher = new IndexSearcher(dir);
		Term t = new Term(filedName, searchString);
		Query query = new TermQuery(t);
		
		TopDocs topDocs = searcher.search(query, 100);
		ScoreDoc[] hits = topDocs.scoreDocs;
		
		int hitCount = hits.length;
		searcher.close();
		return hitCount;
	}
}
 

通过批量删除的方式进行更新操作

我们的例子删除和重新添加的只是一个文档对象。如果你需要删除和添加多个文档对象,最好批量地进行这些操作。步骤如下:

1.打开IndexReader对象。

2.删除所有需要删除的Document对象。

3.关闭IndexReader对象。

4.打开IndexWriter对象。

5.添加所有需要添加的Document对象。

6.关闭IndexWriter对象。

要记住:对文档对象的批量删除和索引操作,总要比交替地删除和添加操作速度快。

0
0
分享到:
评论

相关推荐

    Lucene索引的基本操作

    为了确保索引操作的正确性,通常会编写测试代码。例如,我们可以创建一个简单的测试类`L_IndexingTest`,使用`DirectoryReader`和`IndexSearcher`来查询索引: ```java public class L_IndexingTest { public ...

    Oracle--索引的基本操作与存储效率的体验.docx

    在本实验中,我们将深入探讨索引的基本操作和其对存储效率的影响。 首先,我们创建和删除索引。例如,为选课表(SCRZ0112)的课程号列(Cno)创建位图索引,这将加速对课程号的查找。位图索引适用于那些具有较少...

    索引介绍聚集索引和非聚集索引

    #### 一、索引的基本概念 在数据库中,索引是一种特殊的文件结构,它的主要目的是为了提高数据检索的速度。索引通过创建一种数据结构(例如B树)来实现这一点,这种结构允许数据库管理系统能够快速定位到数据所在的...

    Oracle 创建索引的基本规则

    ### Oracle 创建索引的基本规则 在Oracle数据库管理中,创建合适的索引对于提高查询效率、减少数据处理时间具有重要作用。本文将围绕Oracle创建索引的基本规则进行深入探讨,旨在帮助读者更好地理解如何根据不同的...

    词索引表的建立——查找操作在字符串处理中的应用

    词索引表的建立——查找操作在字符串处理中的应用 在计算机应用中,信息检索是非常重要的一个领域。为了提高图书馆数目检索的效率,建立书名关键词索引是非常必要的。这可以实现读者快速检索书目的自动化,即读者...

    实 验 三 索引及数据操作

    ### 实验三:索引及数据操作 #### 实验目的 本实验旨在通过实践操作让学生熟练掌握数据库中索引的创建与删除方法、SQL语句的应用以及数据的插入、修改和删除技巧。这些技能对于后续深入学习数据库管理和优化至关...

    索引的基本操作与存储效率的体验

    索引虽然能提高查询效率,但会降低数据插入、更新和删除(DML)操作的速度,因为每次DML操作都需要同步更新索引。因此,在修改性能需求远大于检索性能的场景下,可能需要牺牲部分索引带来的好处,以保障整体系统性能...

    MySQL Innodb 索引原理详解

    在深入探讨MySQL Innodb索引之前,我们先了解几种基本的树形数据结构,包括二叉搜索树、B树、B+树以及B*树。 ##### 1.1 搜索二叉树(Binary Search Tree) 搜索二叉树是一种特殊的二叉树,每个节点至多有两个子...

    操作系统课程设计 便于直接存取的索引文件结构

    混合索引的基本思想是在索引节点中设置一部分直接指针,用于直接访问前几个数据块;然后,设置一个或多个间接指针,每个间接指针指向一个包含其他数据块指针的索引块。例如,可以设置一级间接索引、二级间接索引等,...

    oracle、sql数据库批量建索引

    首先,让我们了解索引的基本概念。索引是数据库为了快速定位数据而创建的一种数据结构,类似于书籍的目录。它减少了数据库执行查询时扫描整个表的次数,从而显著提高了查询速度。在数据量庞大的情况下,索引的重要性...

    Mysql数据库索引创建、索引删除、索引失效场景详解

    索引的失效场景包括:更新或删除索引列,使用不带索引的全表扫描操作,使用`SELECT *`而不是明确列出索引列,使用`NOT IN`、`&lt;&gt; ALL()`或`NOT EXISTS`等操作,以及在`WHERE`子句中使用了函数或表达式。此外,索引也...

    oracle的索引学习

    首先,理解索引的基本概念。索引是一种特殊的数据结构,它存储在表空间中,用于加速对表数据的访问。当执行查询时,Oracle数据库能够利用索引来避免全表扫描,转而执行索引扫描,从而提高查询速度。然而,创建和维护...

    索引

    本篇文章将深入探讨索引的基本原理、类型以及其在实际应用中的作用。 首先,索引的创建基于某种数据结构,如B树、哈希表或位图等。B树( Balanced Tree)是最常见的一种,它允许数据在磁盘上保持有序,同时支持快速...

    视图和索引的创建和使用实验报告.pdf

    视图和索引可以结合使用,例如可以使用视图 V_IS 和索引 i_sdept_sno 查询信息系学生基本情况: SELECT * FROM V_IS WHERE sno = '5'; 本实验报告总结了视图和索引的创建、修改、使用等知识点,并结合实验步骤和...

    MySQL 索引最佳实践

    - **理解索引**:了解索引的基本概念、作用以及不同类型的索引。 - **设置最佳索引**:根据应用程序需求来设计最适合的索引方案。 - **解决常见限制**:了解MySQL索引的一些常见限制,并找到相应的解决方案。 #### ...

    MySQL索引类型大汇总

    普通索引是最基本的索引类型,没有任何限制。可以通过以下三种方式创建普通索引: * 创建索引:`CREATE INDEX indexName ON mytable(username(length))` * 修改表结构:`ALTER mytable ADD INDEX [indexName] ON ...

    Mysql-索引原理分析

    理解这些基本概念对于优化查询性能至关重要。例如,选择合适的索引类型、合理设计主键、以及考虑是否需要为辅助列创建非聚集索引,都是数据库设计时需要考虑的问题。在实际应用中,应根据查询模式和数据量来调整索引...

    oracle索引机制分析

    基本索引概念 索引是数据库管理系统(DBMS)为了加快数据检索速度而采用的一种数据结构。Oracle提供了多种类型的索引,每种索引都有其特定的优势和适用场景。索引的基本目的是通过减少磁盘I/O次数来提高查询性能。...

    数据库索引设计与优化

    一、数据库索引的基本概念 数据库索引是一种数据结构,它提供了对表中数据的快速访问路径。常见的索引类型有B树(B-Tree)、哈希索引(Hash Index)和位图索引(Bitmap Index)。B树索引适用于范围查询和排序操作,...

Global site tag (gtag.js) - Google Analytics