全文检索(Full-Text Retrieval)是计算机程序通过扫描文章中的每一个词,对每一个词建立一个索引,指明该词在文章中出现的次数和位置。当用户查询时根据建立的索引查找,类似于通过字典的检索字表查字的过程。关于全文检索的特性,我们要知道:1,只处理文本。2,不处理语义。3,搜索时英文不区分大小写。4,结果列表有相关度排序。
参考:
lucene需要通过分词器(analyzer)拆分句子、词组,以便存储和搜索,本项目用的是IK分词器2012V5版本。
友情提示:创建索引的分词方法须与搜索时的分词方法一致。
我们会从数据库拿到一些数据,每个字段对应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)。
-
调用lucene的搜索方法,并设置出现条件:必须出现(MUST)、应该出现(SHOULD)、不出现(MUST_NOT)
-
设置搜索结果的权重(setBoost)来控制排序
-
设置sort函数控制排序
- lucene排序---相关度与其他组合排序
- lucene sort field 排序字段
- lucene按时间排序显示
- lucene/IK查询怎么在得分一样的情况下按照另一个字段排序
- Lucene sort 排序
- 简单总结:先在创建单条索引时,向文档加入可比较域,如NumericDocValuesField,搜索时定义sort,并用sortfield初始化,然后search(query,limit,sort,[hasScoreCalculate=]true,[hasMaxScore=]true)确保排序的同时计算分数。
-
关键词替换为包含html class的关键词,以便高亮
- 增(add):同创建索引
- 删(delete):删除指定索引(deleteDocuments),删除全部索引(deleteAll)
- 改(update):更新索引,机制为先删除再创建(updateDocument)
- 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 --获取数据库数据
- com.search
- config.properties
- WebRoot
- index.html --搜索页面
- initial.html --初始化索引表页面
- manager.html --索引表增删改页面
- src
-
数据模型 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) |
-
搜索数据组装 EntryUtil.java
2.1 json:空集合和搜索结果数量。(原因:搜索不到结果,或关键词长度小于2)
数据样例:
{ “result” :[], “testCount”:”0” }
2.2 test的json数据和test的搜索结果数量。(最多不超过500条)
数据样例:
{ “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 增删改和初始化索引表
成功:
[{“errCode”:0}]
失败:
[{“errCode”:-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点)
-
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点)
- 关闭连接
-
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)
-
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)
-
Output.java --异常信息打印
5.1 boolean createFile(String fileName,String filecontent) 创建文件
5.2 boolean writeFileContent(String filepath,String newstr) 向文件中写入内容
直接初始化索引,详见1.2。
- java获取post参数
- 判断type
- 判断id是否存在
- 若存在:判断visible:1为更新索引操作;0为删除索引操作
- 若不存在:判断visible:1为插入索引;0不做任何操作
大致流程:
0 | 1 | → | 2 | → | 3 | → | 4 | → | 5 | → | 6 | → | 7 | → | 8 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
1 | 1.1 | → | 1.2 | → | 1.3 | → | return | ||||||||
↓ | ↘ | 4.3 | → | 4.8 | → | 4.4 | → | return | |||||||
2 | 1.4 | → | 3.1 | → | 4.5 | → | 4.7 | → | 3.5 | → | 3.4 | → | 3.6 | → | return |