该项目类似于百度搜索引擎,在搜索框内输入一个 Java API 文档的关键字,对后端发出请求,后端将处理后的若干条查询结果返回给前端展示,并且按照一定的权重排序展示出来。每条搜索结果包含了标题、描述、URL,点击标题可以跳转到官方文档。
项目主要分为3个模块:
引入 ansj 依赖,将本地的 API 文档 进行分词处理,以便计算每个词的权重。
<dependency>
<groupId>org.ansjgroupId>
<artifactId>ansj_segartifactId>
<version>5.1.6version>
dependency>
将分出来的词,放入 List 中。
List<String> words = ToAnalysis.parse(str);
正向索引就是:通过title(文档ID),去找value(目标文档),然后确定出包含的 文档 URL、content,将这些文档展示给用户。

正排索引的表中,tilte 是不重复的,每一个 title 对应唯一的 URL 和 content。
构建: 遍历每个文档的标题,并且存储其 URL 和 content。
如何提取本地的.html文档的内容?
使用 Java 正则表达式 去除HTML文件中的<标签>, 只保留文本格式。
return contentBuilder.toString()
// 首先去掉
.replaceAll(".*?" , " ")
// 去掉标签
.replaceAll("<.*?>", " ")
// 去掉转义字符
.replaceAll("&.*?;", " ")
.replaceAll("\\s+", " ")
.trim();
倒排索引就是:通过value(关键词),去找key(文档ID),然后将找到的结果,即这些文档,展示给用户;

倒排索引的表中,(word, weight) 的组合是不重复的,每一组合都会有对应的文档ID,单词权重。
构建: 遍历每个文档中的所有词,每个文档插入 countDifferentWord 条数据到表中,(word[i], docid, weight(word[i]))。
如何计算单词的权重?
因为按照用户的搜索逻辑来说,文档标题的权重是自然要比内容中的单词权重高一些的。所以在计算时,适当的给标题提高权重。
int weight = titleCount * 10 + contentCount;
query 关键词,先对 query 进行分词,得到 queryList。queryList 中可能出现多个关键词。针对每个关键词去倒排索引中查找,每个关键词都有若干条结果,把所有结果添加到 List中。全文的前120字+后120字)、URL。出现的问题: 由于数据量非常大(正排索引1万条, 倒排索引20万条),导致构建索引的过程非常耗时,同时搜索时性能也比较差。
优化的过程:
最开始 —— 单线程+当行插入——耗时>3小时。
第一次优化:单线程+批量插入——耗时约3分钟。
使用 mapper.xml + @Mapper 的方式执行 SQL 语句。
原因:单纯的 @Insert 的使用,无法完成SQL的批量插入。
正排索引每次插入10条,因为正排索引的单条数据量就比较大(包含了文本内容)。
倒排索引每次插入10000条,单条数据量小。
<mapper namespace="com.wangshaoyu.search.indexer.mapper.IndexDatabaseMapper">
<insert id="batchInsertForwardIndexes" useGeneratedKeys="true" keyProperty="docId" keyColumn="docid">
insert into forward_indexes (title, url, content) values
<foreach collection="list" item="doc" separator=", ">
(#{doc.title}, #{doc.url}, #{doc.content})
foreach>
insert>
<insert id="batchInsertInvertedIndexes">
insert into inverted_indexes (word, docid, weight) values
<foreach collection="list" item="record" separator=", ">
(#{record.word}, #{record.docId}, #{record.weight})
foreach>
insert>
mapper>
ThreadPoolExecutor executor = new ThreadPoolExecutor(
8, 20, 30, TimeUnit.SECONDS,
new ArrayBlockingQueue<>(5000),
(Runnable task) -> {
Thread thread = new Thread(task);
thread.setName("批量插入线程");
return thread;
},
new ThreadPoolExecutor.AbortPolicy()
);
-- 插入数据后,再构建索引
ALTER TABLE `searcher`.`inverted_indexes`
ADD INDEX `INDEX_word_weight` (`word` ASC, `weight` DESC);
;
项目访问地址:http://1.15.76.95:8019
主页:

查询结果页:

点击跳转到官方文档:

总结:
提示:这里对文章进行总结:
以上就是今天的学习内容,该项目类似于百度搜索引擎,在搜索框内输入一个 Java API 文档的关键字,对后端发出请求,后端将处理后的若干条查询结果返回给前端展示,并且按照一定的权重排序展示出来。之后的学习内容将持续更新!!!