当前位置 博文首页 > 令狐_JackieHao的博客:【原来那么简单/大数据】随随便便开发一
? 小编最近写的项目=============》有问题咨询可以加小哥微信:JL1714873054。如果觉得不错可以点一波关注,谢谢,后台看到私信一定会回复,没有回复请谅解。可以关注我的微信公众号:CodeLinghu ,预约毕设,预约项目,查看精彩的项目博客分享。
本项目的重点是搜索/索引。所以我们首先认识一下所谓的搜索功能。
传统的搜索功能流程如图01-00.
? 图01-00
以上搜索功能是目前企业中较为传统的一种搜索方式,其特点就是数据量少,承载不了高并发。
本项目所采用的搜索理论基础方案如图01-01.
? 图01-01
使用新方案的优势:
数据查询有两种方案:
所谓顺序查询就是通过用户检索的内容进行字符串匹配,遍历所有的文档,当匹配到相同字符串便查询到当前文件,没有查到则继续扫描下一个文件,直到扫描完成所有文件。
倒排索引是指先将海量数据进行分词,形成一个索引表,查询时先查询索引表,通过索引表查询指定文件,这样可以做到有效去重查询相同内容文本的时间。为了做到倒排索引,我们才用的则是全文检索技术------lucene
原始文档数据:
文档:
Document
,文档 Document
中包含了许多 域 Field
分析文档(分词):
分析文档就是分词。将文档中的内容进行词组划分。
索引文档:
索引文档是为了更好地搜索。分词形成了词汇单元,通过索引词汇单元快速找到需要被索引到的内容。
可以通过官方网站下载lucene,也可以在小哥留的资料包里下载
解压后:
PS:queryparser
:查询解析器
使用以上三个文件就可以实现本次项目中Lucene的功能。
也在这个文件夹下面:
导入到mysql的效果:
使用 DAO
接口实现类获取mysql中的数据:
package cn.linghu.dao;
import cn.linghu.pojo.Sku;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.List;
/**
*
*/
public class SkuDaoImpl implements SkuDao {
public List<Sku> querySkuList() {
// 数据库链接
Connection connection = null;
// 预编译statement
PreparedStatement preparedStatement = null;
// 结果集
ResultSet resultSet = null;
// 商品列表
List<Sku> list = new ArrayList<Sku>();
try {
// 加载数据库驱动
Class.forName("com.mysql.jdbc.Driver");
// 连接数据库
connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/lucene", "root", "123456");
// SQL语句
String sql = "SELECT * FROM tb_sku";
// 创建preparedStatement
preparedStatement = connection.prepareStatement(sql);
// 获取结果集
resultSet = preparedStatement.executeQuery();
// 结果集解析
while (resultSet.next()) {
Sku sku = new Sku();
sku.setId(resultSet.getString("id"));
sku.setName(resultSet.getString("name"));
sku.setSpec(resultSet.getString("spec"));
sku.setBrandName(resultSet.getString("brand_name"));
sku.setCategoryName(resultSet.getString("category_name"));
sku.setImage(resultSet.getString("image"));
sku.setNum(resultSet.getInt("num"));
sku.setPrice(resultSet.getInt("price"));
sku.setSaleNum(resultSet.getInt("sale_num"));
list.add(sku);
}
} catch (Exception e) {
e.printStackTrace();
}
return list;
}
}
\1. 采集数据
\2. 创建Document文档对象
\3. 创建分析器(分词器)
\4. 创建IndexWriterConfifig配置信息类
\5. 创建Directory对象,声明索引库存储位置
\6. 创建IndexWriter写入对象
\7. 把Document写入到索引库中
\8. 释放资源
package cn.linghu.test;
import cn.linghu.dao.SkuDao;
import cn.linghu.dao.SkuDaoImpl;
import cn.linghu.pojo.Sku;
import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.analysis.standard.StandardAnalyzer;
import org.apache.lucene.document.*;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.IndexWriterConfig;
import org.apache.lucene.index.Term;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.FSDirectory;
import org.apache.lucene.store.MMapDirectory;
import org.junit.Test;
import org.wltea.analyzer.lucene.IKAnalyzer;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
/**
* 索引库维护
*/
public class TestIndexManager {
/**
* 创建索引库
*/
@Test
public void createIndexTest() throws Exception {
//1. 采集数据
SkuDao skuDao = new SkuDaoImpl();
List<Sku> skuList = skuDao.querySkuList();
//文档集合
List<Document> docList = new ArrayList<>();
for (Sku sku : skuList) {
//2. 创建文档对象
Document document = new Document();
//创建域对象并且放入文档对象中
/**
* 是否分词: 否, 因为主键分词后无意义
* 是否索引: 是, 如果根据id主键查询, 就必须索引
* 是否存储: 是, 因为主键id比较特殊, 可以确定唯一的一条数据, 在业务上一般有重要所用, 所以存储
* 存储后, 才可以获取到id具体的内容
*/
document.add(new StringField("id", sku.getId(), Field.Store.YES));
/**
* 是否分词: 是, 因为名称字段需要查询, 并且分词后有意义所以需要分词
* 是否索引: 是, 因为需要根据名称字段查询
* 是否存储: 是, 因为页面需要展示商品名称, 所以需要存储
*/
document.add(new TextField("name", sku.getName(), Field.Store.YES));
/**
* 是否分词: 是(因为lucene底层算法规定, 如果根据价格范围查询, 必须分词)
* 是否索引: 是, 需要根据价格进行范围查询, 所以必须索引
* 是否存储: 是, 因为页面需要展示价格
*/
document.add(new IntPoint("price", sku.getPrice()));
document.add(new StoredField("price", sku.getPrice()));
/**
* 是否分词: 否, 因为不查询, 所以不索引, 因为不索引所以不分词
* 是否索引: 否, 因为不需要根据图片地址路径查询
* 是否存储: 是, 因为页面需要展示商品图片
*/
document.add(new StoredField("image", sku.getImage()));
/**
* 是否分词: 否, 因为分类是专有名词, 是一个整体, 所以不分词
* 是否索引: 是, 因为需要根据分类查询
* 是否存储: 是, 因为页面需要展示分类
*/
document.add(new StringField("categoryName", sku.getCategoryName(), Field.Store.YES));
/**
* 是否分词: 否, 因为品牌是专有名词, 是一个整体, 所以不分词
* 是否索引: 是, 因为需要根据品牌进行查询
* 是否存储: 是, 因为页面需要展示品牌
*/
document.add(new StringField("brandName", sku.getBrandName(), Field.Store.YES));
//将文档对象放入到文档集合中
docList.add(