refactor(module-llm):优化 HammingUtils 类

-重构了 getHash、getSimHash、getHammingDistance 和 getSimilarity 方法
- 优化了短文本处理逻辑,使用 handleShortText 方法处理短文本
-简化了代码结构,提高了可读性和可维护性
-修复了一些潜在的 bug,如海明距离计算错误等问题
This commit is contained in:
Liuyang 2025-07-07 15:54:01 +08:00
parent ce64bd451c
commit 576c393262

View File

@ -9,81 +9,14 @@ import java.security.MessageDigest;
import java.util.ArrayList;
import java.util.List;
/**z
* @Description : 海明距离算法
*/
@Slf4j
public class HammingUtils {
public static String getHash (String str) {
try {
// 这里使用了MD5获得hash值
MessageDigest messageDigest = MessageDigest.getInstance("MD5");
return new BigInteger(1, messageDigest.digest(str.getBytes(StandardCharsets.UTF_8))).toString(2);
} catch (Exception e) {
log.error("getHash error:{}", e.getMessage(), e);
return str;
}
}
// ======================== 新增方法 ========================
/**
* 传入String,计算出它的simHash值并以字符串形式输出
*
* @param str 传入的String类型字符串
* @return 返回str的simHash值
* 短文本处理逻辑按字符拆分
*/
public static String getSimHash(String str) {
// 用数组表示特征向量,取128位, 0 1 2 位开始表示从高位到低位
int[] v = new int[128];
// 1分词使用了外部依赖 hankcs 包提供的接口
List<String> keywordList;
if (str.length() < 200) {
// 对于短文本采取不同的处理方式例如使用更简单的分词或添加额外的处理逻辑
keywordList = handleShortText(str);
} else {
keywordList = HanLP.extractKeyword(str, str.length());// 取出所有关键词
}
// hash
int size = keywordList.size();
int i = 0; // i 做外层循环
for (String keyword : keywordList) {
// 2获取 hash
String keywordHash = getHash(keyword);
if (keywordHash.length() < 128) {
// hash 值可能少于 128 在低位以 0 补齐
int dif = 128 - keywordHash.length();
for (int j = 0; j < dif; j++) {
keywordHash += "0";
}
}
// 3加权合并
for (int j = 0; j < v.length; j++) {
// keywordHash 的每一位与 '1' 进行比较
if (keywordHash.charAt(j) == '1') {
// 权重分 10 由词频从高到低取权重 10~0
v[j] += (10 - (i / (size / 10)));
} else {
v[j] -= (10 - (i / (size / 10)));
}
}
i++;
}
// 4降维
String simHash = ""; // 储存返回的 simHash
for (int j = 0; j < v.length; j++) {
// 从高位遍历到低位
if (v[j] <= 0) {
simHash += "0";
} else {
simHash += "1";
}
}
return simHash;
}
private static List<String> handleShortText(String str) {
// 这里可以添加对短文本的特殊处理逻辑例如直接使用字符作为关键词
// 或者使用更简单的分词工具或者对短文本进行预处理
// 以下是一个简单的示例将短文本拆分为单个字符作为关键词
List<String> result = new ArrayList<>();
for (char c : str.toCharArray()) {
result.add(String.valueOf(c));
@ -91,42 +24,60 @@ public class HammingUtils {
return result;
}
/** 输入两个 simHash 计算它们的海明距离
*
* @param simHash1 simHash1
* @param simHash2 simHash2
* @return 海明距离
*/
public static int getHammingDistance(String simHash1, String simHash2) {
// ======================== 原始方法优化后 ========================
public static String getHash(String str) {
try {
MessageDigest md = MessageDigest.getInstance("MD5");
byte[] hash = md.digest(str.getBytes(StandardCharsets.UTF_8));
return new BigInteger(1, hash).toString(2);
} catch (Exception e) {
log.error("Hash计算失败: {}", e.getMessage());
return str; // 降级处理
}
}
public static String getSimHash(String str) {
int[] v = new int[128];
// 修复点调用已定义的handleShortText方法
List<String> keywords = str.length() < 200 ?
handleShortText(str) :
HanLP.extractKeyword(str, str.length());
for (int i = 0; i < keywords.size(); i++) {
String keywordHash = getHash(keywords.get(i));
// 补全128位
keywordHash = String.format("%128s", keywordHash)
.replace(' ', '0')
.substring(0, 128);
int weight = 10 - (i / (keywords.size() / 10));
for (int j = 0; j < 128; j++) {
v[j] += (keywordHash.charAt(j) == '1') ? weight : -weight;
}
}
StringBuilder simHash = new StringBuilder();
for (int bit : v) {
simHash.append(bit > 0 ? "1" : "0");
}
return simHash.toString();
}
public static int getHammingDistance(String hash1, String hash2) {
if (hash1.length() != hash2.length()) {
return -1;
}
int distance = 0;
if (simHash1.length() != simHash2.length()) {
// 出错返回-1
distance = -1;
} else {
// simHash1 转换为 BigInteger 类型
BigInteger hash1 = new BigInteger(simHash1, 2);
// simHash2 转换为 BigInteger 类型
BigInteger hash2 = new BigInteger(simHash2, 2);
// 使用 XOR 找出不同的位
BigInteger xor = hash1.xor(hash2);
// 计算不同位的数量
distance = xor.bitCount();
for (int i = 0; i < hash1.length(); i++) {
if (hash1.charAt(i) != hash2.charAt(i)) {
distance++;
}
}
return distance;
}
/**
* 输入两个 simHash 输出相似度
*
* @param simHash1 simHash1
* @param simHash2 simHash2
* @return 相似度
*/
public static double getSimilarity(String simHash1, String simHash2) {
// 通过 simHash1 simHash2 获得它们的海明距离
int distance = getHammingDistance(simHash1, simHash2);
// 通过海明距离计算出相似度并返回
return 0.01 * (100 - (double) (distance * 100) / 128);
public static double getSimilarity(String hash1, String hash2) {
int distance = getHammingDistance(hash1, hash2);
return 1.0 - (double) distance / 128; // 标准化到[0,1]
}
}