开发者学堂课程【Lucene 知识精讲与实战(上): 入门案例(搜索过程)】学习笔记,与课程紧密联系,让用户快速学习知识。
课程地址:https://developer.aliyun.com/learning/course/700/detail/12335
入门案例(搜索过程)
内容介绍:
一、搜索流程
二、搜索代码
一、搜索流程
前文用 lunk 小工具来查看索引,文档,测试搜索后,用代码怎么来实现,。下面通过代码来进行演示。
首先回到 idea 当中,这里写一下 test,在上面加上 test 的注解。
package cn.itheima.test;
import org.junit.Test;
日/中*
*测试搜索过程
public class Testsearch {
@Test
public void testIndexSearch()
流程如下;
1.创建分词器(对搜索的关键词进行分词使用)
索引的时候创建分词器是有道理的,因为要把文档的内容提取出来,先分成一个词,然后组成,所以来到索引库,文档和缩影都存到索引库。搜索的时候来创建分词器,是对搜索的关键词要进行分词。进行切分词的原因是搜索的不一定是某一个词,比如说在百度中,在搜索引擎上输华为手机,华为手机如果用标准分词器分的话,它会分成4个字然后对这4个词进行分别的进行搜索,再进行并交集或者是求并集。
使用分词器,不但说要使用分词器,还要必须和创建索引的时候使用的分时器一模一样。注意:分时器要和创建索引的时候使用的分词器一模一样,因为不同的分词器它的分词效果不一样。举个例子,标准分词器认为中文是一个字,有一些第三方分磁器它的分值效果非常它进行语义分析,有带语义分析的功能,有可能一句话,就不是一个字一个词了,一模一样他认为是然后一样是一个词,然后还有分词器,这又是一个词,他可能就进行语义识别了。如果说创建索引的时候,切的索引它是一个字就是一个词,而搜索的时候使用的是一种第三方分词器,它进行语义分析,切出来这个词跟索引库里的词它对应不上,明显就是查不到结果的。所以说这也会影响查询结果的准确度。所以创建索引和搜索的时候必须要使用同样的分析。
2.创建查询对象
3.设置搜索关键词
4.创建 Directory 目录对象,指定索引库的位置
设置从哪个库中去搜索,所以说要创建 Direct 目录对象,指定索引库的位置,指定完索引库的位置就指定从库来进行搜索。
5.创建输入流对象
在创建索引库的时候,创建的助理对象,这里搜索要把内容给读进来,所以要创建输入流。
6.创建搜索对象
7.搜索,并返回结果
8.获取结果集
结果有了,要解析结果集,叫做获取结果集
9.遍历结果集
10.关闭流
二、搜索代码
//1.创建分词器(对搜索的关键词进行分词使用)
//注意:分词器要和创建索引的时候使用的分词器一模一样
//分词器在创建索引的时候,用的是标准分词器,这里搜索的时候必须也要使用标准分词器,选择lucene的包。
Analyzer analyzer=newStandardAnalyzer();
//2.创建查询对象
//第一个参数:默认查询域,如果查询的关键字中带搜索的域名,则从指定域中查询,如果不带域名则从,
//默认搜索域中查询
//第二个参数:使用的分词器
要传参数,点进去看一下它的源码。先写第一个参数,默认查询域,然后第二个参数,第二个参数使用的分词器。默认查询域来看默认的查询域,域有价格,有名称等等,想从哪个域进行查询,这里从name这个域中查,所以这里域名写name,再来看,后边是他使用的分词器,分词器是标准分词器,把这个作为参数给它传进去,再来往下,搜索关键字叫做华为,可以搜华为手机,搜华为手机的话,从默认搜索域中查。默认查询域仲裁。如果说想写具体的域名也可以,这里也可以跟写这里不一样的域名,比如说这个域名它是还有 brand name 叫做品牌。
这里可以写 brand name,然后冒号,域名跟查询的关键字要用冒号隔开,会从这个品牌名称当中开始查,它叫做华为手机,如果说这个域名不写,它就会从name默认查询中查,这里把这个就省略了。默认查询域就是如果查询的关键字中搜索的域名则从指定中查询,如果不带域名,域名则默认搜索域中查询,默认搜索域中,所以说它第一个参数是直接用的,下面在查询关键字当中,如果带域名了,就从指定的域查,如果直接写的是关键字不带域名,就从默认查询域中进行查询。
这个写好了之后,发现报错这里要抛一个异常,叫做 throw exception,叫做查询对象创建出来了。
QueryParser queryParser=new QueryParser("name",analyzer);
//3.设置搜索关键词
Query query=queryParser.parse(“华为手机");
//4.创建 Directory 目录对象,指定索引库的位置
创建 directory 目录对象,目录对象指定它的所用库的位置, Directory 不能选错。这里要抛一个异常 throw exception。
这个叫做 filed 查询对象创建出来了,创建出来之后,下面继续在下边创建 directory,目录对象指定它的所用库的位置,当时创建索引的时候用的是 filed、system、directory、文件、系统目录,这里它是抽象类型的。
索引库位置在E盘的dir目录,把这个位置复制,跟之前一样粘贴,粘贴之后,创建输入流,之前输出流叫 index writer,这里输入流叫做 index reader,然后index reader 等于 new index reader 可以 new directly open,发现 open 报错。是因为它也是抽象类型的,抽象类型的不能new。index reader,用 directory,然后reader看有没有文件目录的输入流,然后点 open,打开索引库,这样创建出来了。
Directory dir=FSDirectory.open(Paths.get("E:\\dir));
//5.创建输入流对象
IndexReader indexReader=DirectoryReader.open(dir);
//6.创建搜索对象
再来往下创建搜索对象,搜索 index search,里面传的输入流对象,这个是搜索对象。这里这个叫做 index search,通过 index search 搜索对象搜索 search 的时候,
IndexSearcher indexSearcher=newIndexSearcher(indexReader);
//7.搜索,并返回结果
//第二个参数:是返回多少条数据用于展示,分页使用
这里要传查询对象,查询的关键字华为手机传进去,后边这个参数要返回多少条数据,这里查询查询的数据一共有100多万条,假如说有500条还好,如果说这里100多万条,要有50多万条的数据都符合华为手机的话,查出来这个数据量特别多,如果特别多的话都展示出来,肯定有可能说给的程序给的电脑就有可能卡死了。
所以说这里要分页的话,返回多少条数据,返回多少条展示,每次返回10条展示,这样的话返回的数据量比较小,速度会比较快一些。这里写100,无论查询出来的结果是几万条甚至十几万条,只返回前100条数据,然后给展示出来而已。
这里写一下第二个参数是什么?是返回多少条数据用于展示,然后分页使用,这里返回就返回10条,这个叫做 Top 结果叫做 Top dox,就是返回来的结果,从返回来的这个结果当中获取结果集。返回来的应该是一个使用类型的数组。
TopDocs topDocs=indexSearcher.search(query,10);
//8.获取结果集
ScoreDocl scoreDocs=topDocs.scoreDocs;
//9.遍历结果集
下边要遍历结果,在遍历结果之前要判断一下它为不为空,如果不为空的情况下,才能对它进行for循环遍历,要不然容易报数组越界这样的错误。
if(scoreDocs!= null) {
for (ScoreDoc scoreDoc :scoreDocs){
//获取查询到的文档唯一标识,文档id,这个 id 是 lucene 在创建文档的时候自动分配的 int docID=scoreDoc.doc;
//通过文档id,读取文档
Document doc=indexSearcher.doc(dociD);
System.out.println("================= = = = = = = = = = = = = = = = = = = = = = = = = = “ );
//通过域名,从文档中获取域值
System.out.println("===id==" + doc.get("id"));
System.out.println("===name=="+ doc.get("name")); System.out.println("===price=="+ doc.get("price")); System.out.println("===image=="+ doc.get("image"));
System.out.println("===brandName==" + doc.get("brandName"));
System.out.println("===categoryName=="+ doc.get("categoryName"));
这回获取查询到的结果集的总数打印。
TopDocs topDocs=indexSearcher.search(query,10);
//获取查询到的结果集的总数,打印
System.out.println("=======count=======");topDocs.totalHits;
运行一下,看看这个结果怎么样?搜的是叫做华为手机,结果一共查华为手机查询出来24,147条。
结果如下:
=price== 76300
=--image=-https://m.360buyimg.com/mobilecms/s720x720 ifs/t13615/278/1165446825/333206/55afe3aa/5a1bd4f4Nf02c806f.ipg!q7e.ipg.webp
===brandName==华为
---categoryName==手机T
----------- ..........
===id==18182117880
===name==华为(HUAWEI)华为mate10 手机亮黑色6G+128G===price==53100
=-=image==https://m.360buyimg.com/mobilecms/s720x720 jfs/t13615/278/1165446825/333206/55afe3aa/5a1bd4f4Nf02c806f.ipg!q7e.ipg.webp
===brandName==华为===categoryName==手机
= = = = = = = = = = ----
===id==18182117882