您的位置:首页 > 编程语言 > Java开发

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

2017-04-27 15:06 363 查看

什么是全文检索

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());
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  lucene Analyzer javaEE
相关文章推荐