Lucene学习笔记

一.Lucene简介

Lucene是apache软件基金会发布的一个开放源代码的全文检索引擎工具包,由资深全文检索专家Doug Cutting所撰写,它是一个全文检索引擎的架构,提供了完整的创建索引和查询索引,以及部分文本分析的引擎,Lucene的目的是为软件开发人员提供一个简单易用的工具包,以方便在目标系统中实现全文检索的功能,或者是以此为基础建立起完整的全文检索引擎,Lucene在全文检索领域是一个经典的祖先,现在很多检索引擎都是在其基础上创建的,思想是相通的。

1.什么是全文检索

全文检索是计算机程序通过扫描文章中的每一个词,对每一个词建立一个索引,指明该词在文章中出现的次数和位置。当用户查询时根据建立的索引查找,类似于通过字典的检索字表查字的过程。

2.为什么使用全文检索

传统通过数据库搜索,sql语句,模糊查询,大量模糊查询,数据不精准,对数据库性能有很大影响

而全文检索是通过文档中存放索引搜索,对服务器压力,数据处理,优化,减轻数据库压力,有很大帮助。

  • (1)SQL只能针对数据库表搜索,不能直接针对硬盘上的文本搜索
  • (2)SQL没有相关度排名
  • (3)SQL搜索结果没有关健字高亮显示
  • (4)SQL需要数据库的支持,数据库本身需要内存开销较大,例如:Oracle
  • (5)SQL搜索有时较慢,尤其是数据库不在本地时,超慢,例如:Oracle

3.全文检索原理

0fa27cd429d12d7a40a4a5bda2a39a6c676.jpg

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

索引流程:采集数据--->构建文档对象--->创建索引(将文档写入索引库)。

搜索流程:创建查询--->执行搜索--->渲染搜索结果。

二.Lucene入门示例

1.需求:

    使用Lucene实现电商项目中图书类商品的索引和搜索功能

2.配置步骤说明:

    2.1 搭建环境

    2.2创建索引库

    2.3搜索索引库

3.配置步骤

    3.1 第一部分:搭建环境(创建项目,导入需要的jar包)

        3.1.1 第一步 : 下载Lucene:

            官方网站:http://lucene.apache.org/             

            下载地址:http://archive.apache.org/dist/lucene/java/

            下载版本:4.10.3(要求:jdk1.7及以上)

            核心包 lucene-core-4.10.3.jar(常用api)

a80a7f2a832f3da2c85e73018d0e2a79681.jpg

        3.1.2 第二步 : 创建项目,导入包           

                mysql5.1驱动包:mysql-connector-java-5.1.7-bin.jar

                核心包:lucene-core-4.10.3.jar

                分析器通用包:lucene-analyzers-common-4.10.3.jar

                查询解析器包:lucene-queryparser-4.10.3.jar

                项目结构如下图

                4606e97294abcb68dabfbf75f7140228d73.jpg

 

    3.2 第二部分 :创建索引 

        3.2.1 采集数据

            Lucene 全文检索,不是直接查询数据库,所以需要先将数据采集出来

           (1) 创建实体类

            3fb7e258bacd8de1ee251597fdf653551f5.jpg

           (2)创建一个BookDao类

    

package cn.gzsxt.lucene.dao;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

import cn.gzsxt.lucene.pojo.Book;

public class BookDao {
	public List<Book> getAll() {
		// 数据库链接
		Connection connection = null;
		// 预编译statement
		PreparedStatement preparedStatement = null;
		// 结果集
		ResultSet resultSet = null;
		// 图书列表
		List<Book> list = new ArrayList<Book>();
		try {
			// 加载数据库驱动
			Class.forName("com.mysql.jdbc.Driver");
			// 连接数据库
			connection = DriverManager.getConnection(
					"jdbc:mysql://localhost:3306/lucene", "root", "gzsxt");

			// SQL语句
			String sql = "SELECT * FROM book";
			// 创建preparedStatement
			preparedStatement = connection.prepareStatement(sql);

			// 获取结果集
			resultSet = preparedStatement.executeQuery();

			// 结果集解析
			while (resultSet.next()) {
				Book book = new Book();
				book.setBookId(resultSet.getInt("id"));
				book.setName(resultSet.getString("name"));
				book.setPrice(resultSet.getFloat("price"));
				book.setPic(resultSet.getString("pic"));
				book.setDescription(resultSet.getString("description"));
				list.add(book);
			}
		} catch (Exception e) {
			e.printStackTrace();
			
		}finally {
			
			if(null!=resultSet){
				try {
					resultSet.close();
				} catch (SQLException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
			if(null!=preparedStatement){
				try {
					preparedStatement.close();
				} catch (SQLException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
			if(null!=connection){
				try {
					connection.close();
				} catch (SQLException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		}
		return list;
	}
}

            (3) 创建测试类 BookDaoTest

package cn.gzsxt.lucene.test;

import java.util.List;

import org.junit.Test;
import cn.gzsxt.lucene.dao.BookDao;
import cn.gzsxt.lucene.pojo.Book;

public class BookDaoTest {

	@Test
	public void getAll(){
		BookDao dao = new BookDao();
		List<Book> books = dao.getAll();
		
		for (Book book : books) {
			System.out.println("图书id:"+book.getBookId()+",图书名称:"+book.getName());
		}
	}
}

            (4) 测试结果,获取数据成功

7db190850ba703e4ddb6f4c54ad374c9334.jpg

        3.2.2 将数据转换为Lucene文档

        Lucene是使用文档类型来封装数据的,所有需要先将采集的数据转换成文档类型。其格式为:

d5d7d61db89b6c91fef49c8eed43dc627cd.jpg

修改BookDao,新增一个方法,转换数据

public List<Document> getDocuments(List<Book> books){
		// Document对象集合
		List<Document> docList = new ArrayList<Document>();
		// Document对象
		Document doc = null;
		for (Book book : books) {
			// 创建Document对象,同时要创建field对象
			doc = new Document();
			// 根据需求创建不同的Field
			StoredField id = new StoredField("id", book.getId());
			TextField name = new TextField("name", book.getName(), Store.YES);
			FloatField price = new FloatField("price", book.getPrice(), Store.YES);
			StoredField pic = new StoredField("pic", book.getPic());
			TextField desc = new TextField("desc", book.getDescription(), Store.NO);
			// 把域(Field)添加到文档(Document)中
			doc.add(id);
			doc.add(name);
			doc.add(price);
			doc.add(pic);
			doc.add(desc);

			docList.add(doc);
	}
	return docList;
}

 

        3.2.3 将文档写入索引库,创建索引

        说明:Lucene是在将文档写入索引库的过程中,自动完成分词、创建索引的。因此创建索引库,从形式上看,就是将文档写入索引库!

        修改测试类,新增createIndex方法

@Test
	public void createIndex(){
		try {
			BookDao dao = new BookDao();
			
			// 分析文档,对文档中的field域进行分词
			Analyzer analyzer = new StandardAnalyzer();
			// 创建索引
			// 1) 创建索引库目录
			Directory directory = FSDirectory.open(new File("F:\\lucene\\0719"));
			// 2) 创建IndexWriterConfig对象
			IndexWriterConfig cfg = new IndexWriterConfig(Version.LATEST, analyzer);
			// 3) 创建IndexWriter对象
			IndexWriter writer = new IndexWriter(directory, cfg);
			// 4) 通过IndexWriter对象添加文档对象(document)
			writer.addDocuments(dao.getDocuments(dao.getAll()));
			
			// 5) 关闭IndexWriter
			writer.close();
			System.out.println("创建索引库成功");
			
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

   3.3 第三部分 : 搜索索引

    3.3.1 说明

        搜索的时候,需要指定搜索哪一个域(也就是字段),并且,还要对搜索的关键词做分词处理。

    3.3.2 执行搜索

        修改测试类,新增searchDocumentByIndex方法

@Test
	public void searchDocumentByIndex(){
		try {
			// 1、 创建查询(Query对象)
			// 创建分析器
			Analyzer analyzer = new StandardAnalyzer();
			QueryParser queryParser = new QueryParser("name", analyzer);
			Query query = queryParser.parse("name:java教程");
			// 2、 执行搜索
			// a) 指定索引库目录
			Directory directory = FSDirectory.open(new File("F:\\lucene\\0719"));
			// b) 创建IndexReader对象
			IndexReader reader = DirectoryReader.open(directory);
			// c) 创建IndexSearcher对象
			IndexSearcher searcher = new IndexSearcher(reader);
			// d) 通过IndexSearcher对象执行查询索引库,返回TopDocs对象
			// 第一个参数:查询对象
			// 第二个参数:最大的n条记录
			TopDocs topDocs = searcher.search(query, 10);
			// e) 提取TopDocs对象中前n条记录
			ScoreDoc[] scoreDocs = topDocs.scoreDocs;
			System.out.println("查询出文档个数为:" + topDocs.totalHits);
			for (ScoreDoc scoreDoc : scoreDocs) {
				// 文档对象ID
				int docId = scoreDoc.doc;
				Document doc = searcher.doc(docId);
				// f) 输出文档内容
				System.out.println("===============================");
				System.out.println("文档id:" + docId);
				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"));
			}
			// g) 关闭IndexReader
			reader.close();
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

        测试结果:

084c352985871a7163b7f916ca64fd33b70.jpg

 

根据代码可以发现,Lucene全文检索,可以实现对关键词做分词,在执行搜索功能,并且结果更精确

转载于:https://my.oschina.net/u/4117400/blog/3040592

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值