资讯专栏INFORMATION COLUMN

Lucene学习笔记

justCoding / 2678人阅读

摘要:全文检索概述数据分类结构化数据具有固定格式或者长度有限的数据,例如数据库中的表。语句非结构化数据与结构化数据对立,例如邮件网页文档。

全文检索概述 数据分类

结构化数据:具有固定格式或者长度有限的数据,例如数据库中的表。【SQL语句】

非结构化数据:与结构化数据对立,例如:邮件、网页、word文档。【数据扫描、全文检索】

半结构化数据:介于两者之间,例如xml或者json格式的数据。

全文检索过程


反向索引(倒排表):由字符串到文件的映射是文件到字符串映射的反向过程。

索引创建

索引检索

Lucene数学模型 文档、域、词元

文档是Lucene搜索和索引的原子单位,文档为包含一个或者多个的容器,而域则是依次包含“真正的”被搜索的内容,域值通过分词技术处理,得到多个词元

For Example,一篇小说(斗破苍穹)信息可以称为一个文档,小说信息又包含多个域,例如:标题(斗破苍穹)、作者、简介、最后更新时间等等,对标题这个域采用分词技术又可以得到一个或者多个词元(斗、破、苍、穹)。

词元权重计算

Term Frequency(tf):此term在文档中出现的次数,tf越大则该词元越重要

Document Frequency(df):有多少文档包含此term,df越大该词元越不重要

空间向量模型如下:

计算夹角的余弦值,夹角越小,余弦值越大,分值越大,从而相关性越大。

Lucene文件结构 层次结构

index:一个索引存放在一个目录中;

segment:一个索引中可以有多个段,段与段之间是独立的,添加新的文档可能产生新段,不同的段可以合并成一个新段;

document:文档是创建索引的基本单位,不同的文档保存在不同的段中,一个段可以包含多个文档;

field:域,一个文档包含不同类型的信息,可以拆分开索引;

term:词,索引的最小单位,是经过词法分析和语言处理后的数据。

正向信息

按照层次依次保存了从索引到词的包含关系:index-->segment-->document-->field-->term。

反向信息

反向信息保存了词典的倒排表映射:term-->document

配置Lucene开发环境

Lucene是ASF的开源项目,最新版本是5.2.1,但是鉴于网络上大多数教程使用的是Lucene 4,在本文中使用的版本是Lucene 4.3.1,下载解压,到对应目录找到以下的jar包并添加到构建路径中。

如果使用maven其maven依赖如下:


	org.apache.lucene
	lucene-core
	4.3.1


	org.apache.lucene
	lucene-queryparser
	4.3.1


	org.apache.lucene
	lucene-queries
	4.3.1


	org.apache.lucene
	lucene-highlighter
	4.3.1


	org.apache.lucene
	lucene-analyzers-smartcn
	4.3.1


	org.apache.lucene
	lucene-analyzers-common
	4.3.1
Lucene常用功能介绍 索引创建 创建索的关键类

创建索引的示例代码:

/**
 * 索引创建
 */
@Test
public void createIndex() {
	
	// 创建一个分词器(指定Lucene版本)
	Analyzer analyzer = new StandardAnalyzer(Version.LUCENE_43);	
	// IndexWriter配置信息(指定Lucene版本和分词器)
	IndexWriterConfig indexWriterConfig = new IndexWriterConfig(Version.LUCENE_43, analyzer); 
	// 设置索引的打开方式
	indexWriterConfig.setOpenMode(OpenMode.CREATE_OR_APPEND);
	// 创建Directory对象和IndexWriter对象
	Directory directory = null;
	IndexWriter indexWriter = null;
	try {
		directory = FSDirectory.open(new File("Lucene_index/test"));
		
		// 检查Directory对象是否处于锁定状态(如果锁定则进行解锁)
		if (IndexWriter.isLocked(directory)) {
			IndexWriter.unlock(directory);
		}
		
		indexWriter = new IndexWriter(directory, indexWriterConfig);
	} catch (IOException e) {
		e.printStackTrace();
	}
	
	// 创建测试文档并为其添加域
	Document doc1 = new Document();
	doc1.add(new StringField("id", "abcde", Store.YES)); 				  // 添加一个id域,域值为abcde
	doc1.add(new TextField("content", "使用Lucene实现全文检索", Store.YES)); // 文本域
	doc1.add(new IntField("num", 1, Store.YES));						  // 添加数值域
	
	// 将文档写入索引
	try {
		indexWriter.addDocument(doc1);
	} catch (IOException e) {
		e.printStackTrace();
	}
	
	Document doc2 = new Document();
	doc2.add(new StringField("id", "yes", Store.YES)); 				 
	doc2.add(new TextField("content", "Docker容器技术简介", Store.YES)); 
	doc2.add(new IntField("num", 2, Store.YES));						 
	try {
		indexWriter.addDocument(doc2);
	} catch (IOException e) {
		e.printStackTrace();
	}
	
	// 将IndexWriter提交
	try {
		indexWriter.commit();
	} catch (IOException e) {
		e.printStackTrace();
	} finally{
		try {
			indexWriter.close();
			directory.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
}

生成的索引文件如下:

索引检索 索引检索关键类

利用以下的检索程序对前面创建的索引进行检索:

/**
 * 索引检索
 */
@Test
public void searchIndex(){
	
	Directory directory = null;
	DirectoryReader dReader = null;
	try {
		directory = FSDirectory.open(new File("Lucene_index/test"));	// 索引文件
		dReader = DirectoryReader.open(directory);						// 读取索引文件
		IndexSearcher searcher = new IndexSearcher(dReader);			// 创建IndexSearcher对象
		
		Analyzer analyzer = new StandardAnalyzer(Version.LUCENE_43);    // 指定分词技术(标准分词-与创建索引时使用的分词技术一致)
		
		// 创建查询字符串(指定搜索域和采用的分词技术)
		QueryParser parser = new QueryParser(Version.LUCENE_43, "content", analyzer);
		Query query = parser.parse("Docker"); 							// 创建Query对象(指定搜索词)
		
		// 检索索引(指定前10条)
		TopDocs topDocs = searcher.search(query, 10);
		if (topDocs != null) {
			System.out.println("符合条件的文档总数为:" + topDocs.totalHits);
			for (int i = 0; i < topDocs.scoreDocs.length; i++) {
				Document doc = searcher.doc(topDocs.scoreDocs[i].doc);
				System.out.println("id = " + doc.get("id") + ",content = " + doc.get("content") + ",num = " + doc.get("num"));
			}
		}
	} catch (IOException e) {
		e.printStackTrace();
	} catch (ParseException e) {
		e.printStackTrace();
	} finally{
		try {
			dReader.close();
			directory.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
}

运行结果:

Lucene分词器 常见分词器

其中IKAnalyzer需要下载专门的jar包

/**
 * 常见分词器
 */
@Test
public void testAnalyzer(){
	
	final String str = "利用Lucene 实现全文检索";
	Analyzer analyzer = null;
	
	analyzer = new StandardAnalyzer(Version.LUCENE_43); 	// 标准分词
	print(analyzer, str);
	analyzer = new IKAnalyzer();							// 第三方中文分词
	print(analyzer, str);
	analyzer = new WhitespaceAnalyzer(Version.LUCENE_43); 	// 空格分词
	print(analyzer, str);
	analyzer = new SimpleAnalyzer(Version.LUCENE_43); 		// 简单分词
	print(analyzer, str);
	analyzer = new CJKAnalyzer(Version.LUCENE_43);			// 二分法分词
	print(analyzer, str);
	analyzer = new KeywordAnalyzer();						// 关键字分词
	print(analyzer, str);
	analyzer = new StopAnalyzer(Version.LUCENE_43); 		//被忽略词分词器
	print(analyzer, str);

}

/**
 * 该方法用于打印分词器及其分词结果
 * @param analyzer 分词器
 * @param str 需要分词的字符串
 */
public void print(Analyzer analyzer,String str){
	
	StringReader stringReader = new StringReader(str);
	try {
		TokenStream tokenStream = analyzer.tokenStream("", stringReader); 			// 分词
		tokenStream.reset();
		
		CharTermAttribute term = tokenStream.getAttribute(CharTermAttribute.class); // 获取分词结果的CharTermAttribute
		System.out.println("分词技术:" + analyzer.getClass());
		while (tokenStream.incrementToken()) {
			System.out.print(term.toString() + "|");
		}
		System.out.println();
	} catch (IOException e) {
		e.printStackTrace();
	}
}

运行结果:

Query创建



/**
 * 创建Query
 */
@Test
public void createQuery(){
	
	String key = "JAVA EE Lucene案例开发";
	String field = "name";
	String[] fields = {"name","content"};
	Analyzer analyzer = new StandardAnalyzer(Version.LUCENE_43); // 分词器
	
	// 单域查询
	QueryParser parser1 = new QueryParser(Version.LUCENE_43, field, analyzer);
	Query query1 = null;
	try {
		query1 = parser1.parse(key); // 使用QueryParser创建Query
	} catch (ParseException e) {
		e.printStackTrace();
	}
	System.out.println(QueryParser.class + query1.toString());
	
	// 多域查询
	MultiFieldQueryParser parser2 = new MultiFieldQueryParser(Version.LUCENE_43, fields, analyzer);
	try {
		query1 = parser2.parse(key);
	} catch (ParseException e) {
		e.printStackTrace();
	}
	System.out.println(QueryParser.class + query1.toString());
	
	// 短语查询
	query1 = new TermQuery(new Term(field, key));
	System.out.println(TermQuery.class + query1.toString());
	
	// 前缀查询
	query1 = new PrefixQuery(new Term(field, key));
	System.out.println(PrefixQuery.class + query1.toString());
	
	// 短语查询
	PhraseQuery query2 = new PhraseQuery();
	query2.setSlop(2); // 设置短语间的最大距离是2
	query2.add(new Term(field, "Lucene"));
	query2.add(new Term(field, "案例"));
	System.out.println(PhraseQuery.class + query2.toString());
	
	// 通配符查询
	query1 = new WildcardQuery(new Term(field, "Lucene?"));
	System.out.println(WildcardQuery.class + query1.toString());
	
	// 字符串范围搜索
	query1 = TermRangeQuery.newStringRange(field, "abc", "azz", false, false);
	System.out.println(TermRangeQuery.class + query1.toString());
	
	// 布尔条件查询
	BooleanQuery query3 = new BooleanQuery();
	query3.add(new TermQuery(new Term(field, "Lucene")),Occur.SHOULD); // 添加条件
	query3.add(new TermQuery(new Term(field, "案例")),Occur.MUST); 
	query3.add(new TermQuery(new Term(field, "案例")),Occur.MUST_NOT); 
	System.out.println(BooleanQuery.class + query3.toString());
}

运行结果:

IndexSearcher常用方法

检索关键类

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/64432.html

相关文章

  • elasticsearch学习笔记(三)——Elasticsearch的核心概念

    摘要:下面来通过引出的核心概念和的前世今生是最先进功能强大的搜索库。任何一个服务器随时可能故障或宕机,此时可能就会丢失,因此可以为每个创建多个副本。默认每个索引个个个,最小的高可用配置是台服务器核心概念和数据库核心概念数据库行表 下面来通过lucene引出Elasticsearch的核心概念 1、lucene和elasticsearch的前世今生 lucene是最先进、功能强大的搜索库。但是...

    wow_worktile 评论0 收藏0
  • elasticsearch学习笔记(一)——大白话告诉你什么是elasticsearch

    摘要:对于倒排索引,也就是在全文检索时对每个词建立索引是采用倒排索引的方式。由于不是由记录来确定属性值,而是由属性值来确定记录的位置,因而称为倒排索引。 什么是elasticsearch? wiki上面的解释是: Elasticsearch is a search engine based on the Lucene library. It provides a distributed, m...

    darkbaby123 评论0 收藏0
  • 学习笔记CB011:lucene搜索引擎库、IKAnalyzer中文切词工具、检索服务、查询索引、导

    摘要:开源免费搜索引擎库,语言开发。,开源中文切词工具。中文需转发送,端读取按解析,启动方法聊天界面。在所有页面公共代码部分增加庞大语料库运用,训练,中文语料转成算法识别向量形式,最强大工具。 影视剧字幕聊天语料库特点,把影视剧说话内容一句一句以回车换行罗列三千多万条中国话,相邻第二句很可能是第一句最好回答。一个问句有很多种回答,可以根据相关程度以及历史聊天记录所有回答排序,找到最优,是一个...

    pf_miles 评论0 收藏0
  • Hadoop学习笔记之:Hadoop的两个部分

    摘要:包含两个部分即分布式文件系统具有高容错性,并且可以被部署在低价的硬件设备之上。管理着整个分布式文件系统,对文件系统的操作如建立删除文件和文件夹都是通过来控制。 本文大部分内容都是从官网Hadoop上来的。其中有一篇介绍HDFS的pdf文档,里面对Hadoop介绍的比较全面了。我的这一个系列的Hadoop学习笔记也是从这里一步一步进行下来的,同时又参考了网上的很多文章,对学习Hadoop中遇到...

    赵连江 评论0 收藏0
  • Neo4j索引笔记之SchemaIndex和LegacyIndex

    摘要:从提供的接口来看,被称作的变量通常是指能够提供全文本检索的能力。这个功能并没有在中被提供,这也是版本保留的原因之一。 neo4j包含schema indexes 和 legacy indexes两种类型,两者理念不同且不可互换或兼容,实际应用中应明确检索需求后采用合适的索引。 schema index vs legacy index 参考neo4j index-confusion s...

    _ipo 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<