Lucene&Solr(之一)-全文索引、入门程序

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/LLLLLiSHI/article/details/70855070


什么是全文检索

1、生活中的数据类型分成:
a、结构化数据:类型固定、格式固定、有限长度的数据。如数据库中的数据
b、非结构化数据:格式不固定、长度不固定的数据。如txt文档、word文档和excel文档、pdf等。

2、数据查询:
结构化数据查询:一般使用sql进行查询( Structure Query Language )。
非结构化数据查询:
a、通过顺序检索,一个一个看……
b、自己写程序,通过IO流读取,匹配字符串。
c、把非结构化数据变成结构化数据。
如:将一段英文文本根据空格拆分,得到单词列表,记录下单词和文本的关系。
查询时只需要查询单词列表,根据单词和文件的对应关系找到文件。基于单词列表创建索引提高查询速度。
这个过程就叫全文检索。

3、全文检索:
这种先建立索引,再对索引进行搜索的过程就叫全文检索。一次创建多次查询。

Lucene实现全文检索的流程

Lucene可以实现全文检索,Lucene是apache旗下一个开源的全文检索引擎工具包。

全文检索的应用场景:
1、搜索引擎:百度一下等
2、电商搜索:淘宝、天猫等
3、论坛搜索:论坛、微博等

Lucene实现全文检索的流程

1、创建索引

原始文档:基于哪些内容进行搜索。
如果是文件搜索,要查询的文件就是原始文档;
搜索引擎:整个互联网的网页内容
电商搜索:所有商品数据

a、获得原始文档

如果是文件:使用IO流读取文件内容

搜索引擎:使用爬虫抓取网页
在internet上采集信息的软件通常称为爬虫或蜘蛛,也成网络机器人。爬取互联网的网页,原理其实是模拟浏览器。
Heritrix:java开发的开源的爬虫,用户可以自己使用它从网上抓取资源,良好的可扩展性,方便用户自定逻辑。
Nutch:apache旗下爬虫程序。lucene&solr都是apache旗下的。
jsoup:java的解析html工具包,可通过DOM、CSS以及类似于JQuery的操作方法取出和操作数据。

电商网站:查询数据库。

b、创建文档对象。每个原始文档对应一个文档对象Document对象。
向Document中添加field,field叫做域。每个field中保存原始文档的一个属性。
每个Document可以有多个field,不同的Document可以有不同的field,同一个Document可以有相同的Field(域 名和域值都相同)
每个文档都有唯一id。

c、分析文档内容
1、先对文档内容根据空格进行字符串拆分,得到一个单词列表。
2、去除标点符号,去除停用词,转换成小写。
最终得到一个词汇单元流(理解为一个一个的单词)。
基于词汇单元流创建索引。索引是一个提高查询速度的数据结构。

d、创建索引库
把索引和文档对象写入磁盘。
索引部分、文档部分、关键字和文档之间的对应关系。

每个单词叫做term,term包括两部分内容,一个关键字和关键字所在的域。
如文件名中包含apache和文件内容中包含的apache是不同的term。


2、查询索引


a、用户查询接口
用户输入查询条件的地方。如百度搜索框

b、接收查询条件
查询对象中包含要搜索的域和要搜索的内容。
lucene基本查询语法:
域的名称:关键字---fileName:lucene

c、查询索引
查询索引库中的索引部分,在某个域上查询关键字。找到关键字得到文档id列表。

d、渲染结果
1、根据id获取文档对象。
2、从文档的field中取内容,展示给用户。
3、关键字高亮显示、相关度排序、分页等效果。

入门程序

1、jar包
lucene核心core文件夹下jar、analyzer-common包、common-io包

2、创建索引库的实现步骤:
1)创建java工程
2)导入lucene相关包

3)创建Directory对象,索引库保存的目录
4)创建IndexWriterConfig对象,参数1:lucene的版本号,参数2:分析器对象,使用标准分析器(英文文本)
5)创建IndexWriter对象,传入IndexWriterConfig对象
6)使用IO流,读取文件信息
7)对应每个文件创建一个Document对象
8)创建field对象,向文档对象中添加域
9)把文档对象写入索引库
10)关闭流

代码实现:
	@Test
	public void createIndex() throws Exception{
		// 3)创建Directory对象,索引库保存的目录
		//Directory directory = new RAMDirectory();		// 索引库存放位置:内存
		Directory directory = FSDirectory.open(new File("F:\\index"));
		// 4)创建IndexWriterConfig对象,参数1:lucene的版本号,参数2:分析器对象,使用标准分析器(英文文本)
		Analyzer analyzer = new StandardAnalyzer();
		IndexWriterConfig config = new IndexWriterConfig(Version.LUCENE_4_10_3, analyzer);
		// 5)创建IndexWriter对象,传入IndexWriterConfig对象
		IndexWriter writer = new IndexWriter(directory, config);
		
		File file = new File("E:\\就业\\课程\\Lucene&Solr\\00.参考资料\\searchsource");
		for (File f : file.listFiles()) {
			// 6)使用IO流,读取文件信息
			String fileName = f.getName();
			String fileContent = FileUtils.readFileToString(f);
			String filePath = f.getPath();
			long fileSize = FileUtils.sizeOf(f);
			// 7)对应每个文件创建一个Document对象
			Document document = new Document();
			// 8)创建field对象,向文档对象中添加域
			// 参数1:域的名称,参数2:域的内容,参数3:是否存储
			Field field1 = new TextField("name", fileName, Store.YES);
			Field field2 = new TextField("content", fileContent, Store.YES);
			Field field3 = new TextField("path", filePath, Store.YES);
			Field field4 = new TextField("size", fileSize + "", Store.YES);
			document.add(field1);
			document.add(field2);
			document.add(field3);
			document.add(field4);
			// 9)把文档对象写入索引库
			writer.addDocument(document);
		}
		// 10)关闭流
		writer.close();
	}



3、查询索引的实现步骤:
1)打开索引库,以读的方式打开。创建IndexReader对象,需要创建Document对象
2)创建IndexSearcher对象,传入IndexReader对象。
3)创建一个查询对象,Query的子类TermQuery,传入两个参数:要搜索的域和要查询的内容
4)执行查询,得到一个文档id列表
5)遍历列表根据文档的id取文档对象
6)从域中取内容,并打印
7)关闭流

代码实现:
	@Test
	public void searchIndex() throws Exception {
		// 1)打开索引库,以读的方式打开。创建IndexReader对象,需要创建Document对象
		Directory directory = FSDirectory.open(new File("F:\\index"));
		IndexReader reader = DirectoryReader.open(directory);
		// 2)创建IndexSearcher对象,传入IndexReader对象。
		IndexSearcher searcher = new IndexSearcher(reader);
		// 3)创建一个查询对象,Query的子类TermQuery,传入两个参数:要搜索的域和要查询的内容
		Query query = new TermQuery(new Term("name", "apache"));
		// 4)执行查询,得到一个文档id列表
		//参数1:查询对象,参数2:查询结果返回的最大记录数,返回最多10个
		TopDocs topDocs = searcher.search(query, 10);
		// 查询的总记录数
		System.err.println("本次查询结果总记录数:" + topDocs.totalHits);
		// 5)遍历列表根据文档的id取文档对象
		for (ScoreDoc scoreDoc : topDocs.scoreDocs) {
			// 去文档id
			int id = scoreDoc.doc;
			// 根据id去文档对象
			Document document = searcher.doc(id);
			// 6)从域中取内容,并打印
			System.out.println("==========================================================================================");
			System.out.println(document.get("name"));
			System.out.println(document.get("path"));
			System.out.println(document.get("size"));
			//System.out.println(document.get("content"));
		}
		// 7)关闭流
		reader.close();
	}

TopDocs

lucene搜索结果可通过TopDocs遍历,提供属性:
totalHits :匹配搜索条件的总记录数
scoreDocs :相关度高的顶部匹配记录,长度<=search方法指定的n。



分析器

在使用分析器之前,需要先查看分析器的分词效果。
每个分析器对象,都有个tokenStream的方法,返回一个TokenStream对象,通过查看TokenStream对象中的内容,分词效果。
使用方法:
1)创建Analyzer对象
2)调用Analyzer的tokenStream,得到TokenStream对象,参数就是待分析的文本。
3)设置一个引用,通过这个引用查看分词效果
4)调用TokenStream的reset方法。初始化这个引用
5)循环遍历TokenStream打印结果。

代码实现:
	@Test
	public void testTokenStream() throws Exception {
		// 创建一个标准分词器
		Analyzer analyzer = new StandardAnalyzer();
		// 获取TokenStream对象
		TokenStream tokenStream = analyzer.tokenStream("此处写域名", "The Spring Framework provides a comprehensive programming and configuration model.");
		// 3)设置一个引用,通过这个引用查看分词效果
		CharTermAttribute charTermAttribute = tokenStream.addAttribute(CharTermAttribute.class);
		// 4)调用TokenStream的reset方法。初始化这个引用
		tokenStream.reset();
		// 5)循环遍历TokenStream打印结果。
		while(tokenStream.incrementToken()) {
			System.out.println(charTermAttribute.toString());
		}
	}


中文分析器

推荐第三方:
这里使用 IKAnalyzer
1、添加jar包到工程中。
2、第三方的配置文件、扩展词典文件、停用字词典文件配置到classpath下

注意:必须保证词典文件编码格式为 utf-8

代码实现:
	@Test
	public void testTokenStream() throws Exception {
		Analyzer analyzer = null;
		// 创建一个标准分词器
		//analyzer = new StandardAnalyzer();
		// 二分法分词
		//analyzer = new CJKAnalyzer();
		//扩展性差
		//analyzer = new SmartChineseAnalyzer();
		// 第三方 IK-analyzer
		analyzer = new IKAnalyzer();
		
		// 获取TokenStream对象
		String str = "Lucene是apache软件基金会4 jakarta项目组的一个子项目,是一个开放源代码的全文检索引擎工具包,但它不是一个完整的全文检索引擎,而是一个全文检索引擎的架构,";
		TokenStream tokenStream = analyzer.tokenStream("此处写域名", str);
		// 3)设置一个引用,通过这个引用查看分词效果
		CharTermAttribute charTermAttribute = tokenStream.addAttribute(CharTermAttribute.class);
		// 4)调用TokenStream的reset方法。初始化这个引用
		tokenStream.reset();
		// 5)循环遍历TokenStream打印结果。
		while(tokenStream.incrementToken()) {
			System.out.println(charTermAttribute.toString());
		}
	}


没有更多推荐了,返回首页