写在前面
在之前的内容中我们已经介绍了创建gitbucket的webHook,使得仓库有更新时自动推送到我们定义的接口;然后Java读取仓库的文件转码写入ES库,这些核心流程已经实现。
2. 基于GitBucket的Hook构建ES检索PDF等文档全栈方案
在在我们的现有系统中,我们已经实现了自动化识别并记录文件类型的能力,无论是纯文本、PDF还是其他格式,都将作为一个ES属性加以记录,这对于后续根据不同文件类型实施针对性处理至关重要。
优化思路
当我们聚焦于Git库与Java开发环境时,我们应当进一步收集和整合文件的关键元数据,诸如文件标签以方便分类和检索,文件作者信息便于版权追踪和贡献度统计,以及文件的更新日期和版本信息,确保每一次变更的历史记录得以精确维护。
若将这一机制与Elasticsearch(ES)相结合,我们将增强对文件内容和元数据的实时索引能力,实现文件识别与Git仓库活动的联动。每当Git库中发生文件的新增、更新或删除操作时,系统都能自动感知并同步至ES,确保索引内容与实际仓库状态始终保持一致,从而实现高效的全文检索和分析。
具体的实现步骤及代码:
索引的映射结构优化
首先ES索引新增了更新时间、active等字段及类型设定。
http
PUT /docwrite
{
"mappings": {
"properties": {
"id": {
"type": "keyword"
},
"title": {
"type": "text",
"analyzer": "ik_max_word"
},
"fileType": {
"type": "keyword"
},
"active": {
"type": "boolean"
},
"upTime":{
"type": "date",
"format": "yyyy-MM-dd HH:mm:ss||epoch_millis"
},
"attachment": {
"properties": {
"content": {
"type": "text",
"analyzer": "ik_smart"
}
}
}
}
}
}
文件作者与标签
作者信息不是解析的文档属性,由于我接收的是git推送消息,所以我直接从消息体属性获取,大致是这样的。
java
String author = getValueByPath(info, "author.name");
文件标签是大多数文档都没有的,所以要么使用自定义的规则,要么就使用文件名分词,更高级的做法是做文章内容的摘要抽取关键词。 我的做法属于自定义规则类,因为我的文件总体上是属于git库的一部分,所以文件自身所在的目录就是它的类型,只要我们在创建文件夹时规范一下就可以了。山不过来我过去,业务上的规范设计能够使得代码逻辑更为简洁!
核心代码如下(当没有上级目录时,记作未定义):
java
// 获取最后一级目录的名称,即文件的标签
String tag = path.getParent() != null ? path.getParent().getFileName().toString() : "未定义";
更新日期的处理
git推送信息的日期字段是不太兼容的文本类型,我们将其变换为ES支持的时间戳类型:
java
import java.time.OffsetDateTime;
import java.time.format.DateTimeFormatter;
private static long dateToTimestamp(String dateStr) {
// 创建一个与ISO8601兼容的日期时间格式化器
DateTimeFormatter formatter = DateTimeFormatter.ISO_OFFSET_DATE_TIME;
// 解析字符串为OffsetDateTime对象
OffsetDateTime offsetDateTime = OffsetDateTime.parse(dateStr, formatter);
// 将OffsetDateTime转换为时间戳(毫秒)
return offsetDateTime.toInstant().toEpochMilli();
}
文件唯一性识别
使用文件相对路径及文件名生成一段Hash值,如果使用SHA-256的算法,内容很长:
但如果截断的话会大幅升高冲突概率(实际上也很低),故而采用MD5摘要算法尚可以接受:
shell
Get INFO: Kelvin,Welcome to 1024!
File name MD5: bc4780da18a605a226798e46971e3fa1
实现代码:
java
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
public static String generateHash(String fileName) throws NoSuchAlgorithmException {
MessageDigest md = MessageDigest.getInstance("MD5"); // 获取MD5实例
byte[] bytesOfFileName = fileName.getBytes(StandardCharsets.UTF_8); // 将文件名转换为字节数组,确保编码正确
md.update(bytesOfFileName); // 更新摘要信息
byte[] digest = md.digest(); // 计算摘要
StringBuilder sb = new StringBuilder();
for (byte b : digest) {
sb.append(Integer.toHexString((b & 0xFF) | 0x100), 1, 3);
}
return sb.toString(); // 这就是MD5哈希值
}
文件的删除
当推送信息里是删除操作时,我们需要将对应的索引文档也删除,那么沿用上面文件的MD5值进行判断,使用效率最高的按ID删除。
但是数据作为企业的宝贵资产,尤其是文档这种体量一般不大,更常见的做法是执行软删除,也就是找到文档将其标记为不可见(我已经提前设计了active
布尔字段来记录)。
存在或发现的问题
- ES7.3实测无法索引docx和doc文档,content有值但是无法解析到附件成为可读的可搜索的内容,附件内容为空(附件中根本没有content这个字段,并非内容为空)。
- 理论上可以直接tika解析它的内容直接传递给ES。