自己动手写搜索引擎(常搜吧历程二#索引#)(Java、Lucene、hadoop)

Lucene的核心索引类:

1、IndexWriter:建立索引的核心组件。

2、Directory:代表一个lucene索引项的位置。

3、Analyzer:对文本内容进行分析的抽象类,具体实现中有停用词切除 、词干分析、大小写切换等功能。

4、Document:可以视作文本经过处理后所对应的对象,由多个字段组成 ,如路径、标题、摘要、修改日期等等。

5、Field:字段 ,对应于文本的某一部分数据,便于检索时根据结果提取。早期版本分为四个类型:Keyword、UnIndexed、UnStored和Text,其主要区别归结于三个方面:是否被分析,是否被索引,是否存储于索引中。但是在最新版本的Lucene中,使用了一种更为统一的形式,也即只有Field一个类,然后使用一些参数来描述这个字段的属性,通过参数组合,可以组合出各种类别,甚至那四种不存在的类别理论上也是可以组合出来。

public Field (String name, String value, Store store, Index index)


下面来看一个例子代码:

package com.qianyan.luceneIndex;

import java.io.IOException;


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;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.FSDirectory;

public class IndexTest {

	public static void main(String[] args) throws IOException{
	
		String[] ids = {"1", "2", "3"};
		String[] names = {"zhangsan", "lisi", "wangwu"};
		String[] addresses = {"shanghai", "beijing", "guangzhou"};
		Analyzer analyzer = new StandardAnalyzer();
		String indexDir = "E:/luceneindex";
		Directory dir = FSDirectory.getDirectory(indexDir);
		//true 表示创建或覆盖当前索引;false 表示对当前索引进行追加
		//Default value is 128
		IndexWriter writer = new IndexWriter(dir, analyzer, true, IndexWriter.MaxFieldLength.LIMITED);
		for(int i = 0; i < ids.length; i++){
			Document document = new Document();
			document.add(new Field("id", ids[i], Field.Store.YES, Field.Index.ANALYZED));
			document.add(new Field("name", names[i], Field.Store.YES, Field.Index.NOT_ANALYZED));
			document.add(new Field("address", addresses[i], Field.Store.YES, Field.Index.ANALYZED));
			writer.addDocument(document);
		}
		writer.optimize();
		writer.close();
	}
	
}
运行后查看 E:/luceneindex 会看到生成的索引文件。


删除索引:

package com.qianyan.luceneIndex;

import java.io.IOException;

import org.apache.lucene.index.IndexReader;
import org.apache.lucene.index.Term;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.FSDirectory;

public class TestDelDocument {

	public static void main(String[] args) throws IOException{
		String indexDir = "E:/luceneindex";
		Directory dir = FSDirectory.getDirectory(indexDir);
		IndexReader reader = IndexReader.open(dir);
		System.out.println(reader.maxDoc());
		//直接根据序号删除索引 注:从0开始
		//reader.deleteDocument(0);
		//根据索引值名删除索引
		//reader.deleteDocuments(new Term("id", "3"));
		System.out.println(reader.numDocs());
		reader.close();
		dir.close();
	}
}


取消删除标记索引:

package com.qianyan.luceneIndex;

import java.io.IOException;

import org.apache.lucene.index.IndexReader;
import org.apache.lucene.index.Term;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.FSDirectory;

public class UnDeleteDocument {

	public static void main(String[] args) throws IOException {
		String indexDir = "E:/luceneindex";
		Directory dir = FSDirectory.getDirectory(indexDir);
		IndexReader reader = IndexReader.open(dir);
		
		System.out.println("before delete:" + reader.numDocs());
		
		reader.deleteDocuments(new Term("id", "1"));
		System.out.println("after delete:" + reader.numDocs());
		
		reader.undeleteAll();
		System.out.println("after undelete:" + reader.numDocs());
		
		reader.close();
		dir.close();
		
	}
}

修改索引(注:在lucene里修改意味着 删除后添加)

package com.qianyan.luceneIndex;

import java.io.IOException;

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.IndexReader;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.Term;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.FSDirectory;

public class UpdateDocument {

	public static void main(String[] args) throws IOException{
		Analyzer analyzer = new StandardAnalyzer();
		String indexDir = "E:/luceneindex";
		Directory dir = FSDirectory.getDirectory(indexDir);
		IndexReader reader = IndexReader.open(dir);
		
		System.out.println("before delete : " + reader.numDocs());
		reader.deleteDocuments(new Term("id", "2"));
		System.out.println("after delete : " + reader.numDocs());
		reader.close();
		
		IndexWriter writer = new IndexWriter(dir, analyzer, false, IndexWriter.MaxFieldLength.LIMITED);
		Document document = new Document();
		document.add(new Field("id", "2", Field.Store.YES, Field.Index.ANALYZED));
		document.add(new Field("name", "Tom", Field.Store.YES, Field.Index.ANALYZED));
		document.add(new Field("address", "tianjin", Field.Store.YES, Field.Index.ANALYZED));
		writer.addDocument(document);	
		writer.close();
		
		reader = IndexReader.open(dir);
		System.out.println("after add : " + reader.numDocs());
		
		dir.close();
		reader.close();
	}
}


在lucene中搜索算法的score简单说是由 tf * idf * boost * lengthNorm计算得来的。

tf:是查询的词在文档中出现的次数的平方根

idf:表示反转文档频率。

boost:激励因子,可以通过setBoost方法设置,需要说明的通过field和doc都可以设置,所设置的值lengthNorm,是由搜索的field的长度决定了,越长文档的分值越低。

控制score的就是设置boost值。

lucene会把计算后,最大分值超过1.0的分值作为分母,其他的文档的分值都除以这个最大值,计算出最终的得分。


document.setBoost(0.5f);  //不太重要

document.setBoost(1.5f);  //比较重要

field.setBoost(0.5f);  //不太重要

field.setBoost(1.5f);  //比较重要


lucene索引效率设置:

setMaxBufferedDocs  16MB

setMergeFactor  10

setMaxMergeDocs  Inter.Max_VALUE;


Directory dir = FSDirectory.getDirectory(indexDir);      //文件系统读取,IO操作

Directory dir = RAMDirectory();       //内存读取,效率高,容量小


你可能感兴趣的:(java,Lucene,云计算)