2018_02_27 全文检索技术----Lucene

数据库中保存的数据,磁盘中保存的数据都可以算做数据,常用的数据分为两种,一种是结构化数据,数据格式固定,长度有限,例如数据库中存储的数据,另一种是非结构化数据,数据格式不固定,长度不固定,例如磁盘中存储的文档数据。


结构化数据的查询可以使用sql查询,查询起来方便。


而非结构化数据的查询就要使用本章中描述的技术,全文检索技术--Lucene,它可以将非结构化数据编程结构化数据,当数据量比较小时,比如一个内容较少的文档,可以适当的使用io流进行读取,完成匹配,对字符串的常规操作,但是当文档内容较大时,需要将文档内容进行合理的拆分,根据得到的词汇列表创建索引,这种先创建索引,然后查询索引的过程就是全文检索。


全文检索的应用领域:对于数据量大,数据机构不固定的数据可以使用全文检索方式进行搜索,例如百度,google等搜索引擎。


索引和搜索流程图:


Lucene的有点就是一次创建索引,多次查询使用


使用Lucene实现全文检索的流程步骤:

1,获取原始文档

2,创建文档对象,为每个原始文档创建一个对应的Document对象,文档中包含若干个域filed,每个文档中包含多个域,不同的document可以包含不同的域,通一个document中可以包含相同的域,每个文档对应一个唯一的id

3,分析文档,分析文档中的内容,分析相关域的内容,

(1)根据控件进行分词,(2)删除标点符号,(3)去除停用词(没有意义的词)(4)将单词统一转换为小写,(5)最终得到一个关键词列表

4,创建索引,

(1)基于分析分档后获得到的关键词列表创建索引(2)把单词和文档的对应关系保存

索引库中包含两部分,一是索引,二是文档对象,索引库维护了索引与文档对象之间的关系,如下:


5,查询索引

(1)创建查询对象,根据查询条件创建一个查询对象Query,Lucene根据query对象查询索引库

(2)执行查询,查询获得一个document文档对象的id列表,根据document对象的id获取文档中的内容

(3)渲染结果,对查询后的结果进行高亮显示,分页显示等等操作


入门程序

1,创建索引库步骤:

第一步:创建一个java工程。

第二步:导入jar包。lucene-core-4.10.3.jar、lucene-analyzers-common-4.10.3.jar、commons-io-2.4.jar

第三步:创建一个Directory对象,指定索引库存放的位置。可以放到内存中也可以放到磁盘上。一般都是保存到磁盘上。

第四步:创建一个IndexWriter对象。需要指定两个参数,一个Directory对象一个是分析器对象。

第五步:循环读取磁盘中XXX/XX目录下的文档。

第六步:创建一个Document对象。

第七步:向Document对象中添加域。

域有三个属性:是否分析、是否索引、是否存储。

是否分析:取决于是否对域的内容进行分词。

是否索引:取决于是否在域上进行搜索。

是否存储:取决于是否展示个用户看。

常用的Field类型:


第八步:把文档对象写入索引库。使用IndexWriter对象。

第九步:关闭IndexWriter对象。

,2,查询索引库步骤:

第一步:创建一个Directory对象。指定索引库存放的目录

第二步:创建一个IndexReader对象。打开索引库

第三步:创建一个IndexSearcher对象,构造方法中需要IndexReader对象。

第四步:创建一个Query对象。两个参数:要搜索的域及要搜索的关键词。

第五步:IndexSearcher执行查询。

第六步:得到一个文档id列表。

第七步:根据id取文档对象。

第八步:从文档对象中取域的内容,展示给用户。

第九步:关闭IndexReader。



package lucene_demo;

import java.io.File;
import org.apache.commons.io.FileUtils;
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.document.Field.Store;
import org.apache.lucene.document.LongField;
import org.apache.lucene.document.StoredField;
import org.apache.lucene.document.TextField;
import org.apache.lucene.index.DirectoryReader;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.IndexWriterConfig;
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;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.FSDirectory;
import org.apache.lucene.util.Version;

public class FirstIndexDemo {
	public static void main(String[] args) {
		try {
			/*testCreateIndex();
			System.out.println("创建索引完毕!!!");*/
			
			testSearchIndex();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	/**
	 * 测试创建索引的方法
	 * @throws Exception 
	 */
	public static void testCreateIndex() throws Exception{
		//创建一个Directory对象,指定索引库存放的位置。可以放到内存中也可以放到磁盘上。一般都是保存到磁盘上。
		//放到内存中
		//Directory directory = new RAMDirectory();
		//放到磁盘上
		Directory directory  = FSDirectory.open(new File("E:\\lucene"));
		//创建一个IndexWriter对象。需要指定两个参数,一个Directory对象一个是分析器对象。
		Analyzer analyzer = new StandardAnalyzer();
		//第一个参数Lucene对应的版本号
		//第二个参数分析器对象
		IndexWriterConfig config = new IndexWriterConfig(Version.LATEST, analyzer);
		IndexWriter indexWriter = new IndexWriter(directory,config);
		//循环读取D:/传智播客/01.课程/04.lucene/01.参考资料/searchsource目录下的文档。
		File dir = new File("E:\\pachong\\text");
		for(File f :dir.listFiles()){
			//取文件名
			String fileName = f.getName();
			//文件路径
			String filePath = f.getAbsolutePath();
			//文件内容
			String fileContent = FileUtils.readFileToString(f);
			//文件大小
			long fileSize = FileUtils.sizeOf(f);
			//创建一个Document对象。
			Document document = new Document();
			//第一个参数:域的名称
			//第二个参数:域的内容
			//第三个参数:是否存储
			Field fileNameField = new TextField("title",fileName,Store.YES);
			Field fileContentField = new TextField("content",fileContent,Store.NO);
			Field filePathField = new StoredField("path",filePath);
			Field fileSizeField = new LongField("size",fileSize,Store.YES);
			//向Document对象中添加域。
			document.add(fileNameField);
			document.add(fileContentField);
			document.add(filePathField);
			document.add(fileSizeField);
			//把文档写入索引库
			indexWriter.addDocument(document);
		}
		//关闭IndexWriter对象
		indexWriter.close();
	}
	
	/**
	 * 测试查询索引库的方法
	 * @throws Exception
	 */
	public static void testSearchIndex() throws Exception{
		//创建一个Directory对象。指定索引库存放的目录	
		Directory directory = FSDirectory.open(new File("E:\\lucene"));
		//创建一个IndexReader对象。打开索引库
		IndexReader indexReader = DirectoryReader.open(directory);
		//创建一个IndexSearcher对象,构造方法中需要IndexReader对象。
		IndexSearcher indexSearcher = new IndexSearcher(indexReader);
		//创建一个Query对象。两个参数:要搜索的域及要搜索的关键词。
		Query query = new TermQuery(new Term("content","个"));
		//IndexSearcher执行查询。
		//第一个参数查询对象,第二个参数返回结果的记录数
		TopDocs topDocs = indexSearcher.search(query, 10);
		//取查询结果的总记录数
		System.out.println("查询记录的总记录数:"+topDocs.totalHits);
		//得到一个文档id列表。
		ScoreDoc[] scoreDocs = topDocs.scoreDocs;
		//根据id取文档对象。
		for (ScoreDoc scoreDoc : scoreDocs) {
			//文档对应的id
			int id = scoreDoc.doc;
			//根据id取Document对象
			Document document = indexSearcher.doc(id);
			//从文档对象中取域的内容,展示给用户。
			System.out.println(document.get("title"));
			System.out.println(document.get("content"));
			System.out.println(document.get("size"));
			System.out.println(document.get("path"));
			System.out.println("----------------------------");
		}
		//关闭IndexReader。
		indexReader.close();
	}
}



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章