Lucene实现全文检索

本文介绍了全文检索的基本概念,包括索引的构建和搜索流程,并通过Lucene这一开源全文检索引擎工具包进行了实例演示。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

    什么是全文检索?全文检索(Full-text Search)是指先建立索引,再对索引进行搜索的过程称为全文检索。

    那么什么是索引呢?

   我们生活中的数据通常分为两种:结构化数据非结构化数据

   结构化数据是指具有固定格式或者有限长度的数据,比如数据库;而非结构化数据是指指不定长或无固定格式的数据,像邮件,word文档等。我们对结构化数据比如数据库进行查询时,一般速度很快,但是像使用like查询采用顺序扫描法,一旦数据量大,效率也会变得很低下,非结构化数据更是如此。

    所以将非结构化数据中的一部分信息提取出来,重新组织,使其变得有一定的结构,然后对此有一定结构的数据进行搜索,从而达到搜索相对快速的目的。这部分从非结构化数据提取出来的信息,就称之为索引。

    虽然创建索引的过程也是非常耗时的,但是索引一旦创建就可以多次使用,全文检索主要处理的是查询,所以耗时间创建索引是值得的。

    全文检索可用于搜索引擎,站内搜索(比如淘宝京东关键字搜索商品),文件系统的搜索等。

    Luceneapache下的一个开源的全文检索引擎工具包(类库)。它的目的是为软件开发人员提供一个简单易用的工具包,以方便的在目标系统中实现全文检索的功能。Lucene提供了完整的查询引擎和索引引擎,部分文本分析引擎。

    

    全文检索的流程分为两大部分:索引流程、搜索流程。

    索引流程:即采集数据-->构建文档对象-->分析文档(分词)-->创建索引。

    搜索流程:即用户通过搜索界面输入-->创建查询-->执行搜索,搜索器从索引库搜索-->渲染搜索结果。

Lucene创建索引的流程(dao层代码略)

public void testIndex() throws Exception {
		// 1. 采集数据:(jdbc采集数据通过BookDao调用方法得到结果集)
		BookDao dao = new BookDaoImpl();
		List<Book> bookList = dao.queryBookList();

		// 2. 遍历book结果集,组装Document数据列表
		Document doc = null;
		List<Document> docs = new ArrayList<>();
		for (Book book : bookList) {
			doc = new Document();
			// 3. 构建Field域,说白了就是将要存储的数据字段需要用到new TextField对象三个参数的构造方法,
			// book中有多个字段,所以创建多个Field对象。
			// 参数一:域的名称,可随意起;参数二:域对应的值;参数三:是否存储
			Field id = new TextField("id", book.getId().toString(), Store.YES);
			Field name = new TextField("name", book.getName(), Store.YES);
			Field price = new TextField("price", book.getPrice().toString(), Store.YES);
			Field pic = new TextField("pic", book.getPic(), Store.YES);
			Field description = new TextField("description", book.getDescription(), Store.YES);
			// 4. 将Field域所有对象,添加到文档对象中。调用Document.add
			doc.add(id);
			doc.add(name);
			doc.add(price);
			doc.add(pic);
			doc.add(description);
			// 组装数据
			docs.add(doc);
		}
		// 5. 创建一个标准分词器(Analyzer与StandardAnalyzer),对文档中的Field域进行分词
		Analyzer analyzer = new StandardAnalyzer();
		// 6. 指定索引储存目录,使用FSDirectory.open()方法。
		FSDirectory directory = FSDirectory.open(new File("D:/Index"));
		// 7. 创建IndexWriterConfig对象,直接new,用于接下来创建IndexWriter对象
		// 参数一:版本号LATEST,使用当前jar包中,最新的;参数二:分词器
		IndexWriterConfig config = new IndexWriterConfig(Version.LATEST, analyzer);
		// 8. 创建IndexWriter对象,直接new
		IndexWriter writer = new IndexWriter(directory, config);
		// 9.添加文档对象到索引库输出对象中writer.addDocuments
		writer.addDocuments(docs);
		// 10. 释放资源IndexWriter.close();
		writer.close();
	}

1.      Document采集数据的目的是为了索引,在索引前需要将原始内容创建成文档(Document),文档(Document)中包括一个一个的域(Field)。

2.        Analyzer分词器在对Document中的内容索引之前需要使用分词器(analyzer)进行分词,主要过程就是分词、过滤两步。

3.        indexWriter是索引过程的核心组件,通过IndexWriter可以创建新索引、更新索引、删除索引操作。IndexWriter需要通过Directory对索引进行存储操作。

4.        Directory描述了索引的存储位置,底层封装了I/O操作,负责对索引进行存储。它是一个抽象类,它的子类常用的包括FSDirectory(在文件系统存储索引),RAMDirectory(在内存存储索引)

搜索流程

     

1 。    创建一个Directory对象,FSDirectory.open指定索引库存放的位置

2.       创建一个IndexReader对象,DirectoryReader.open需要指定Directory对象

3.       创建一个Indexsearcher对象,直接new,需要指定IndexReader对象

4.       创建一个TermQuery对象,直接new,指定查询的域和查询的关键词new Term(域名称,关键词)

5.       执行查询,IndexSearcher.search,需要指定TermQuery对象与查询排名靠多少名前的记录数,得到结果TopDocs

6.       遍历查询结果并输出,TopDocs.totalHits总记录数,topDocs.scoreDocs数据列表,通过scoreDoc.doc得到唯一id,再通过IndexSearcher.doc(id),得到文档对象Document再Document.get(域名称)得到结果

7.       关闭IndexReader对象

        @Test
	public void testQuery() throws Exception{
		// 1. 创建一个Directory对象,FSDirectory.open指定索引库存放的位置
		FSDirectory directory = FSDirectory.open(new File("D:/Index"));
		// 2. 创建一个IndexReader对象,DirectoryReader.open需要指定Directory对象
		IndexReader indexReader = DirectoryReader.open(directory);
		// 3. 创建一个Indexsearcher对象,直接new,需要指定IndexReader对象
		IndexSearcher indexSearcher = new IndexSearcher(indexReader);
		// 4. 创建一个TermQuery对象,直接new,指定查询的域和查询的关键词new Term(域名称,关键词)
		TermQuery query = new TermQuery(new Term("name", "lucene"));
		// 5.执行查询,IndexSearcher.search,需要指定TermQuery对象与查询排名靠多少名前的记录数,得到结果TopDocs
		TopDocs docs = indexSearcher.search(query, 10);
		// 6.遍历查询结果并输出,TopDocs.totalHits总记录数,topDocs.scoreDocs数据列表,
		//通过scoreDoc.doc得到唯一id,再通过IndexSearcher.doc(id),得到文档对象Document,
		//再Document.get(域名称)得到结果
		System.out.println("查询总记录数为:" + docs.totalHits);
		for (ScoreDoc scoreDoc : docs.scoreDocs) {
			//得到文档id
			int id = scoreDoc.doc;
			//得到文档对象
			Document doc = indexSearcher.doc(id);
			System.out.println("id:" + doc.get("id"));
			System.out.println("name:" + doc.get("name"));
			System.out.println("price:" + doc.get("price"));
			System.out.println("pic:" + doc.get("pic"));
			//System.out.println("description:" + doc.get("description"));
		}
		// 7. 关闭IndexReader对象
		indexReader.close();
	}




    








评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值