# Lucene531Example **Repository Path**: company-test_0/Lucene531Example ## Basic Information - **Project Name**: Lucene531Example - **Description**: lucene5.3.1项目样例,全文搜索 - **Primary Language**: Java - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 1 - **Forks**: 0 - **Created**: 2021-08-12 - **Last Updated**: 2023-06-21 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # 全文搜索lucene5.3.1说明文档 [1. 工作原理](#工作原理) [2. 项目结构](#项目结构) [3. 数据结构](#数据结构) [4. 业务逻辑](#业务逻辑) ## 工作原理 全文检索(Full-Text Retrieval)是计算机程序通过扫描文章中的每一个词,对每一个词建立一个索引,指明该词在文章中出现的次数和位置。当用户查询时根据建立的索引查找,类似于通过字典的检索字表查字的过程。关于全文检索的特性,我们要知道:1,只处理文本。2,不处理语义。3,搜索时英文不区分大小写。4,结果列表有相关度排序。 参考: 1. [lucene全文检索精华](https://wenku.baidu.com/view/876b700ee009581b6ad9eb15.html) 2. [全文检索的基本原理](https://blog.csdn.net/forfuture1978/article/details/4711308) 3. [Lucene5.3.1 API](http://lucene.apache.org/core/5_3_1/core/index.html) ### (1) 分词器 lucene需要通过分词器(analyzer)拆分句子、词组,以便存储和搜索,本项目用的是IK分词器2012V5版本。 友情提示:创建索引的分词方法须与搜索时的分词方法一致。 ### (2) 创建索引 我们会从数据库拿到一些数据,每个字段对应lucene的每个域(field),经过分词处理的域的组合形成一个文档(document)。如下图: * 数据表 | | 字段1 | 字段2 | | --------| ------ | ------ | | id=1 | abc | abc | | id=2 | abc | abc | | id=3 | abc | abc | * lucene文档 | | 域1 | 域2 | | --------| ------ | ------ | | 索引1 | a,b,c | a,b,c | | 索引2 | a,b,c | a,b,c | | 索引3 | a,b,c | a,b,c | 当然,需要事先设置文档的保存路径(directory),设置文档的名字(type),创建写入器(IndexWriter),写入器导致数据每次的改动都要保存(commit)和关闭(close)。 ### (3) 搜索 * 调用lucene的搜索方法,并设置出现条件:必须出现(MUST)、应该出现(SHOULD)、不出现(MUST_NOT) * [多域搜索 MultiFieldQueryParser](http://www.cnblogs.com/xudong-bupt/archive/2013/05/08/3065297.html) * [通配符搜索 WildcardQuery](https://blog.csdn.net/u012965373/article/details/44783817) * [模糊搜索 FuzzyQuery](https://blog.csdn.net/iamaboyy/article/details/7747095) * [精确搜索 TermQuery](https://yq.aliyun.com/articles/45354) * [更多搜索方法参考1](https://blog.csdn.net/pangliang_csdn/article/details/51752665) * [更多搜索方法参考2](https://www.cnblogs.com/linjiqin/archive/2013/06/08/3125861.html) * 设置搜索结果的权重(setBoost)来控制排序 * 设置sort函数控制排序 * [lucene排序---相关度与其他组合排序](https://blog.csdn.net/JackieLiuLixi/article/details/40149101) * [lucene sort field 排序字段](http://www.fengxiaochuang.com/?p=160) * [lucene按时间排序显示](https://www.cnblogs.com/lingyi/articles/6249664.html) * [lucene/IK查询怎么在得分一样的情况下按照另一个字段排序](https://ask.csdn.net/questions/679733) * [Lucene sort 排序](https://blog.csdn.net/jackieliulixi/article/details/40149313) * 简单总结:先在创建单条索引时,向文档加入可比较域,如NumericDocValuesField,搜索时定义sort,并用sortfield初始化,然后search(query,limit,sort,[hasScoreCalculate=]true,[hasMaxScore=]true)确保排序的同时计算分数。 * 关键词替换为包含html class的关键词,以便高亮 ### (4) 索引表的增删改 * 增(add):同创建索引 * 删(delete):删除指定索引(deleteDocuments),删除全部索引(deleteAll) * 改(update):更新索引,机制为先删除再创建(updateDocument) >[参考样例1](https://blog.csdn.net/napoay/article/details/53074118) >[参考样例2](https://blog.csdn.net/wd501771382/article/details/51190437) ## 项目结构 * Lucene531 * src * com.search * SearchHelper.java --索引表的增删改查 * com.model * SearchModel.java --数据结构模型类 * com.servlet * InitialServlet.java --初始化索引表入口 * ManagerServlet.java --索引表增删改入口 * SearchServlet.java --搜索入口 * com.util * EntryUtil.java --初始化索引表、定时任务、搜索组装 * HelpUtil.java --工具函数 * Output.java --异常信息打印 * SQLUtil.java --获取数据库数据 * config.properties * WebRoot * index.html --搜索页面 * initial.html --初始化索引表页面 * manager.html --索引表增删改页面 ## 数据结构 1. 数据模型 SearchModel.java 与数据库表对应如下:
id(int) name(String) model(String) detail(String) classid(int)
Test id(int) name(varchar) model(varchar) detail(text/varchar) classid(int)

hits(int) updatetime(Date) other(String) visible(Boolean)
Test hits(bigint) updatetime(datetime) other(varchar) visible(bit/smallint)

classname(String)
TestClass classname(varchar)
2. 搜索数据组装 EntryUtil.java 2.1 json:空集合和搜索结果数量。(原因:搜索不到结果,或关键词长度小于2) 数据样例: ```json { “result” :[], “testCount”:”0” } ``` 2.2 test的json数据和test的搜索结果数量。(最多不超过500条) 数据样例: ```json { “result” : [ { “classid”:”1”, ”detail”:”aaa”, ”displayorder”:”1”, ”hits”:”999”, ”id”:”1”, ”model”:”sadsad”, ”name”:”sad”, ”other”:”asd”, ”updatetime”:”2012-08-17 16:22:00”, ”visible”:”true”, ”classname”:”asddd” }, {...}, ..., {...} ], “testCount”:”500” } ``` 2.3 增删改和初始化索引表 成功: ```json [{“errCode”:0}] ``` 失败: ```json [{“errCode”:-1}] ``` ## 业务逻辑 ### 函数实现 1. EntryUtil.java --初始化索引表、定时任务、搜索组装 1.1 static 静态构造函数 * 第一次访问会初始化索引表和设置定时初始化索引表任务。 1.2 Boolean initializeIndex() 初始化索引表 * 创建索引表 * 返回标志符 1.3 void setTime() 定时初始化索引表任务 * 设置每天24:00调用初始化索引表函数 1.4 String searchServer(String keywords,String type) 返回搜索数据 * 过滤关键词长度小于2 * 搜索关键词,并获得搜索结果数量 * 数据组装(详见[数据结构](#数据结构)第2点) 2. SQLUtil.java --获取数据库数据 2.1 static SQLUtil getInstance() 获取数据库实例 2.2 Connection getConnection() 数据库连接 * 获取配置文件中的链接字符串 * 设置数据库驱动 * 获取连接并返回 2.3 ArrayList getProductList() 获取test列表 * 执行SQL语句 * 填充数据模型(详见[数据结构](#数据结构)第1点) * 关闭连接 2.4 SearchModel getProductChangedData(String id) 获取test改动数据 * 执行SQL语句 * 填充数据模型(详见[数据结构](#数据结构)第1点) * 关闭连接 3. HelpUtil.java --工具函数 3.1 String filterHtml(String html) 过滤危险字符 * 去除js的  * 去除html及其属性 * 将标点符号 Unicode空白符替换为“|” 3.2 Boolean filterString_setBootst(String s) 判断是否常用词 * 常用词包括aa,bb,cc,dd 3.3 String[] mergeIdentical(String[] str) 合并字符串数组中相同的字符串 3.4 String convertToJson(ArrayList datalist) 列表转json 3.5 ArrayList fillDisplayorder(ArrayList datalist) 填充列表的displayorder项,按升序排列 3.6 String responseFormat(String maindata,String dataCount) 数据组装函数 3.7 日期和字符串相互转换函数 * String dateToString(Date date) * Date stringToDate(String dateString) 4. SearchHelper.java --索引表的增删改查 4.1 FSDirectory getDirectory(String type) 创建文档 * 获取配置文件的文档文件夹路径 * 创建文件并返回 4.2 String Token(String str) 分词 * 使用IK分词,词组以“|”隔开 4.3 boolean createIndex(ArrayList datalist, String type) 创建索引 * 创建IK分析器 Analyzer * 创建文档 getDirectory * 配置分析器 IndexWriterConfig * 创建写入器 IndexWriter * 清空文档索引内容 deleteAll * 创建每一条索引 createSingleIndex * 保存和关闭 4.4 boolean createSingleIndex(IndexWriter iwriter, SearchModel data) 创建一条索引 * 新建文档 Document * 设置文档属性 FieldType * setStoreTermVectorOffsets 记录相对增量 * setStoreTermVectorPositions 记录位置信息 * setStoreTermVectors 存储向量信息 * freeze 阻止改动信息 * 创建域 Field * 设置域权重 setBoost * 向文档加入域 add * 写入文档 addDocument 4.5 ArrayList search(String keywords, String type) 查询关键词 * 过滤危险字符 * 打开文档,创建分析器 * 关键词分词 * IK分词数组,权重最小 * 纯数字和字母数组(字母和数字分开) * 纯数字和字母数组(字母和数字可以连在一起),权重最大 * 使用多种搜索方式组合搜索(详见[工作原理](#工作原理)第(3)点) * 查询结果高亮 * FragListBuilder使用SimpleFragListBuilder * FragmentsBuilder使用ScoreOrderFragmentsBuilder * FastVectorHighlighter * getFieldQuery * getBestFragment * 数据按需填充,如限制得分或条数 * 关闭写入器和文档 4.6 int searchByTerm(String field,String name,String type) 查找域目标数量 * 通过精确查询,计算目标数量 4.7 int getSearchCount(String keywords, String type) 获取搜索结果条数 * 与搜索关键词的搜索逻辑相同,搜索完后计数 4.8 索引增删改 * boolean addIndex(SearchModel data, String type) * boolean updateIndex(String id, SearchModel data, String type) * boolean deleteAllIndex(String type) * boolean deleteIndex(String id, String type) 5. Output.java --异常信息打印 5.1 boolean createFile(String fileName,String filecontent) 创建文件 5.2 boolean writeFileContent(String filepath,String newstr) 向文件中写入内容 ### 函数关系 #### InitialServlet 初始化索引表流程 直接初始化索引,详见[1.2](#1-2)。 #### ManagerServlet 索引表增删改流程 1. java获取post参数 2. 判断type 3. 判断id是否存在 * 若存在:判断visible:1为更新索引操作;0为删除索引操作 * 若不存在:判断visible:1为插入索引;0不做任何操作 * visible:[2.4](#2-4) * 更新索引操作:[4.8](#4-8) * 删除索引操作:[4.8](#4-8) * 插入索引:[4.8](#4-8) * 异常:获取数据库数据为空 #### SearchServlet 搜索流程 大致流程: |0|1|→|2|→|3|→|4|→|5|→|6|→|7|→|8| |-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-| |1|[1.1](#1-1)|→|[1.2](#1-2)|→|[1.3](#1-3)|→|return| |↓| | | |↘|[4.3](#4-3)|→|[4.8](#4-8)|→|[4.4](#4-4)|→|return| |2|[1.4](#1-4)|→|[3.1](#3-1)|→|[4.5](#4-5)|→|[4.7](#4-7)|→|[3.5](#3-5)|→|[3.4](#3-4)|→|[3.6](#3-6)|→|return|