|
@@ -1,17 +1,15 @@
|
|
|
package com.tzld.videoVector.service.impl;
|
|
package com.tzld.videoVector.service.impl;
|
|
|
|
|
|
|
|
import com.alibaba.fastjson.JSON;
|
|
import com.alibaba.fastjson.JSON;
|
|
|
-import com.alibaba.fastjson.JSONArray;
|
|
|
|
|
-import com.alibaba.fastjson.JSONObject;
|
|
|
|
|
import com.tzld.videoVector.dao.mapper.pgVector.ContentVectorMapper;
|
|
import com.tzld.videoVector.dao.mapper.pgVector.ContentVectorMapper;
|
|
|
import com.tzld.videoVector.dao.mapper.pgVector.DeconstructVectorConfigMapper;
|
|
import com.tzld.videoVector.dao.mapper.pgVector.DeconstructVectorConfigMapper;
|
|
|
import com.tzld.videoVector.model.po.pgVector.ContentVector;
|
|
import com.tzld.videoVector.model.po.pgVector.ContentVector;
|
|
|
import com.tzld.videoVector.model.po.pgVector.DeconstructContent;
|
|
import com.tzld.videoVector.model.po.pgVector.DeconstructContent;
|
|
|
import com.tzld.videoVector.model.po.pgVector.DeconstructVectorConfig;
|
|
import com.tzld.videoVector.model.po.pgVector.DeconstructVectorConfig;
|
|
|
-import com.tzld.videoVector.model.po.videoVector.deconstruct.DeconstructContentVector;
|
|
|
|
|
import com.tzld.videoVector.service.EmbeddingService;
|
|
import com.tzld.videoVector.service.EmbeddingService;
|
|
|
import com.tzld.videoVector.service.VectorizeService;
|
|
import com.tzld.videoVector.service.VectorizeService;
|
|
|
import com.tzld.videoVector.util.Md5Util;
|
|
import com.tzld.videoVector.util.Md5Util;
|
|
|
|
|
+import com.tzld.videoVector.util.VectorUtils;
|
|
|
import lombok.extern.slf4j.Slf4j;
|
|
import lombok.extern.slf4j.Slf4j;
|
|
|
import org.springframework.stereotype.Service;
|
|
import org.springframework.stereotype.Service;
|
|
|
import org.springframework.util.CollectionUtils;
|
|
import org.springframework.util.CollectionUtils;
|
|
@@ -21,7 +19,6 @@ import javax.annotation.Resource;
|
|
|
import java.util.ArrayList;
|
|
import java.util.ArrayList;
|
|
|
import java.util.Date;
|
|
import java.util.Date;
|
|
|
import java.util.List;
|
|
import java.util.List;
|
|
|
-import java.util.stream.Collectors;
|
|
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
|
* 向量化服务实现类
|
|
* 向量化服务实现类
|
|
@@ -49,7 +46,7 @@ public class VectorizeServiceImpl implements VectorizeService {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
@Override
|
|
|
- public List<DeconstructContentVector> vectorizeContent(DeconstructContent content) {
|
|
|
|
|
|
|
+ public List<ContentVector> vectorizeContent(DeconstructContent content) {
|
|
|
if (content == null || content.getId() == null) {
|
|
if (content == null || content.getId() == null) {
|
|
|
log.error("向量化内容为空或ID为空");
|
|
log.error("向量化内容为空或ID为空");
|
|
|
return new ArrayList<>();
|
|
return new ArrayList<>();
|
|
@@ -67,19 +64,19 @@ public class VectorizeServiceImpl implements VectorizeService {
|
|
|
return new ArrayList<>();
|
|
return new ArrayList<>();
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- List<DeconstructContentVector> allVectors = new ArrayList<>();
|
|
|
|
|
|
|
+ List<ContentVector> allVectors = new ArrayList<>();
|
|
|
|
|
|
|
|
// 按配置逐个向量化
|
|
// 按配置逐个向量化
|
|
|
for (DeconstructVectorConfig config : configs) {
|
|
for (DeconstructVectorConfig config : configs) {
|
|
|
try {
|
|
try {
|
|
|
// 幂等检查:若该 configCode 已有向量则跳过,防止重复向量化
|
|
// 幂等检查:若该 configCode 已有向量则跳过,防止重复向量化
|
|
|
- List<DeconstructContentVector> existing = getVectorsByContentId(content.getId(), config.getConfigCode());
|
|
|
|
|
|
|
+ List<ContentVector> existing = getVectorsByContentId(content.getId(), config.getConfigCode());
|
|
|
if (!CollectionUtils.isEmpty(existing)) {
|
|
if (!CollectionUtils.isEmpty(existing)) {
|
|
|
log.debug("contentId={} 已有 configCode={} 的向量,跳过向量化",
|
|
log.debug("contentId={} 已有 configCode={} 的向量,跳过向量化",
|
|
|
content.getId(), config.getConfigCode());
|
|
content.getId(), config.getConfigCode());
|
|
|
continue;
|
|
continue;
|
|
|
}
|
|
}
|
|
|
- List<DeconstructContentVector> vectors = vectorizeByConfig(content, config);
|
|
|
|
|
|
|
+ List<ContentVector> vectors = vectorizeByConfig(content, config);
|
|
|
if (!CollectionUtils.isEmpty(vectors)) {
|
|
if (!CollectionUtils.isEmpty(vectors)) {
|
|
|
allVectors.addAll(vectors);
|
|
allVectors.addAll(vectors);
|
|
|
}
|
|
}
|
|
@@ -100,9 +97,9 @@ public class VectorizeServiceImpl implements VectorizeService {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
@Override
|
|
|
- public List<DeconstructContentVector> vectorizeByConfig(DeconstructContent content,
|
|
|
|
|
- DeconstructVectorConfig config) {
|
|
|
|
|
- List<DeconstructContentVector> vectors = new ArrayList<>();
|
|
|
|
|
|
|
+ public List<ContentVector> vectorizeByConfig(DeconstructContent content,
|
|
|
|
|
+ DeconstructVectorConfig config) {
|
|
|
|
|
+ List<ContentVector> vectors = new ArrayList<>();
|
|
|
|
|
|
|
|
// 提取文本内容
|
|
// 提取文本内容
|
|
|
List<String> texts = extractTexts(content, config);
|
|
List<String> texts = extractTexts(content, config);
|
|
@@ -137,22 +134,21 @@ public class VectorizeServiceImpl implements VectorizeService {
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- // 构建向量实体
|
|
|
|
|
- DeconstructContentVector vector = new DeconstructContentVector();
|
|
|
|
|
|
|
+ // 构建向量实体(直接使用 PG ContentVector)
|
|
|
|
|
+ ContentVector vector = new ContentVector();
|
|
|
vector.setContentId(content.getId());
|
|
vector.setContentId(content.getId());
|
|
|
vector.setTaskId(content.getTaskId());
|
|
vector.setTaskId(content.getTaskId());
|
|
|
vector.setConfigCode(config.getConfigCode());
|
|
vector.setConfigCode(config.getConfigCode());
|
|
|
vector.setSourceField(config.getSourceField());
|
|
vector.setSourceField(config.getSourceField());
|
|
|
vector.setSourcePath(config.getSourcePath());
|
|
vector.setSourcePath(config.getSourcePath());
|
|
|
- vector.setVectorDimension(vectorData.size());
|
|
|
|
|
- vector.setVectorData(JSON.toJSONString(vectorData));
|
|
|
|
|
|
|
+ vector.setEmbedding(JSON.toJSONString(vectorData));
|
|
|
vector.setSourceText(truncatedText);
|
|
vector.setSourceText(truncatedText);
|
|
|
vector.setTextHash(textHash);
|
|
vector.setTextHash(textHash);
|
|
|
vector.setEmbeddingModel(embeddingModel);
|
|
vector.setEmbeddingModel(embeddingModel);
|
|
|
vector.setSegmentIndex(segmentIndex++);
|
|
vector.setSegmentIndex(segmentIndex++);
|
|
|
vector.setSegmentTotal(texts.size());
|
|
vector.setSegmentTotal(texts.size());
|
|
|
- vector.setCreateTime(new Date());
|
|
|
|
|
- vector.setUpdateTime(new Date());
|
|
|
|
|
|
|
+ vector.setCreatedAt(new Date());
|
|
|
|
|
+ vector.setUpdatedAt(new Date());
|
|
|
|
|
|
|
|
vectors.add(vector);
|
|
vectors.add(vector);
|
|
|
}
|
|
}
|
|
@@ -183,13 +179,13 @@ public class VectorizeServiceImpl implements VectorizeService {
|
|
|
case "result_json":
|
|
case "result_json":
|
|
|
// 从解构结果JSON中提取
|
|
// 从解构结果JSON中提取
|
|
|
if (StringUtils.hasText(content.getResultJson()) && StringUtils.hasText(sourcePath)) {
|
|
if (StringUtils.hasText(content.getResultJson()) && StringUtils.hasText(sourcePath)) {
|
|
|
- texts.addAll(extractFromJson(content.getResultJson(), sourcePath));
|
|
|
|
|
|
|
+ texts.addAll(VectorUtils.extractFromJson(content.getResultJson(), sourcePath));
|
|
|
}
|
|
}
|
|
|
break;
|
|
break;
|
|
|
default:
|
|
default:
|
|
|
// 尝试从result_json中提取自定义字段
|
|
// 尝试从result_json中提取自定义字段
|
|
|
if (StringUtils.hasText(content.getResultJson()) && StringUtils.hasText(sourcePath)) {
|
|
if (StringUtils.hasText(content.getResultJson()) && StringUtils.hasText(sourcePath)) {
|
|
|
- texts.addAll(extractFromJson(content.getResultJson(), sourcePath));
|
|
|
|
|
|
|
+ texts.addAll(VectorUtils.extractFromJson(content.getResultJson(), sourcePath));
|
|
|
}
|
|
}
|
|
|
break;
|
|
break;
|
|
|
}
|
|
}
|
|
@@ -197,120 +193,6 @@ public class VectorizeServiceImpl implements VectorizeService {
|
|
|
return texts;
|
|
return texts;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- /**
|
|
|
|
|
- * 从JSON中提取文本
|
|
|
|
|
- * 支持路径格式:$.final_normalization_rebuild.topic_fusion_result.最终选题.选题
|
|
|
|
|
- * 支持中文 key 和数组路径如 topics[*]
|
|
|
|
|
- */
|
|
|
|
|
- private List<String> extractFromJson(String json, String path) {
|
|
|
|
|
- List<String> results = new ArrayList<>();
|
|
|
|
|
-
|
|
|
|
|
- if (!StringUtils.hasText(json) || !StringUtils.hasText(path)) {
|
|
|
|
|
- return results;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- try {
|
|
|
|
|
- JSONObject jsonObject = JSON.parseObject(json);
|
|
|
|
|
- if (jsonObject == null) {
|
|
|
|
|
- return results;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- // 路径处理(如 $.final_normalization_rebuild.topic_fusion_result.最终选题.选题)
|
|
|
|
|
- if (path.startsWith("$.")) {
|
|
|
|
|
- String pathContent = path.substring(2);
|
|
|
|
|
- // 使用正则分割,支持中文 key
|
|
|
|
|
- List<String> parts = parseJsonPath(pathContent);
|
|
|
|
|
- Object current = jsonObject;
|
|
|
|
|
-
|
|
|
|
|
- for (int i = 0; i < parts.size(); i++) {
|
|
|
|
|
- String part = parts.get(i);
|
|
|
|
|
- if (current == null) {
|
|
|
|
|
- break;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- // 处理数组路径(如 topics[*])
|
|
|
|
|
- if (part.endsWith("[*]")) {
|
|
|
|
|
- String arrayKey = part.substring(0, part.length() - 3);
|
|
|
|
|
- if (current instanceof JSONObject) {
|
|
|
|
|
- JSONArray array = ((JSONObject) current).getJSONArray(arrayKey);
|
|
|
|
|
- if (array != null) {
|
|
|
|
|
- // 递归处理数组元素
|
|
|
|
|
- List<String> remainingParts = parts.subList(i + 1, parts.size());
|
|
|
|
|
- String remainingPath = String.join(".", remainingParts);
|
|
|
|
|
- for (int j = 0; j < array.size(); j++) {
|
|
|
|
|
- Object item = array.get(j);
|
|
|
|
|
- if (remainingParts.isEmpty()) {
|
|
|
|
|
- // 直接取数组元素值
|
|
|
|
|
- if (item instanceof String) {
|
|
|
|
|
- results.add((String) item);
|
|
|
|
|
- }
|
|
|
|
|
- } else {
|
|
|
|
|
- // 继续深入
|
|
|
|
|
- results.addAll(extractFromJson(
|
|
|
|
|
- JSON.toJSONString(item), "$." + remainingPath));
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- return results;
|
|
|
|
|
- } else {
|
|
|
|
|
- // 普通对象路径(支持中文 key)
|
|
|
|
|
- if (current instanceof JSONObject) {
|
|
|
|
|
- current = ((JSONObject) current).get(part);
|
|
|
|
|
- } else {
|
|
|
|
|
- // 当前节点不是对象,无法继续
|
|
|
|
|
- break;
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- // 提取最终值
|
|
|
|
|
- if (current instanceof String) {
|
|
|
|
|
- results.add((String) current);
|
|
|
|
|
- } else if (current instanceof JSONArray) {
|
|
|
|
|
- JSONArray array = (JSONArray) current;
|
|
|
|
|
- for (int i = 0; i < array.size(); i++) {
|
|
|
|
|
- Object item = array.get(i);
|
|
|
|
|
- if (item instanceof String) {
|
|
|
|
|
- results.add((String) item);
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- } catch (Exception e) {
|
|
|
|
|
- log.error("JSON提取失败,path={}, error={}", path, e.getMessage());
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- return results;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- /**
|
|
|
|
|
- * 解析 JSONPath 路径,支持中文 key
|
|
|
|
|
- * 例如:final_normalization_rebuild.topic_fusion_result.最终选题.选题
|
|
|
|
|
- */
|
|
|
|
|
- private List<String> parseJsonPath(String pathContent) {
|
|
|
|
|
- List<String> parts = new ArrayList<>();
|
|
|
|
|
- StringBuilder current = new StringBuilder();
|
|
|
|
|
-
|
|
|
|
|
- for (int i = 0; i < pathContent.length(); i++) {
|
|
|
|
|
- char c = pathContent.charAt(i);
|
|
|
|
|
- if (c == '.') {
|
|
|
|
|
- if (current.length() > 0) {
|
|
|
|
|
- parts.add(current.toString());
|
|
|
|
|
- current = new StringBuilder();
|
|
|
|
|
- }
|
|
|
|
|
- } else {
|
|
|
|
|
- current.append(c);
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- // 添加最后一个部分
|
|
|
|
|
- if (current.length() > 0) {
|
|
|
|
|
- parts.add(current.toString());
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- return parts;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
/**
|
|
/**
|
|
|
* 文本截断
|
|
* 文本截断
|
|
|
* maxLength 为 null 或 <= 0 时不进行截断
|
|
* maxLength 为 null 或 <= 0 时不进行截断
|
|
@@ -341,7 +223,7 @@ public class VectorizeServiceImpl implements VectorizeService {
|
|
|
// 从 pgvector 查询
|
|
// 从 pgvector 查询
|
|
|
ContentVector cached = pgContentVectorMapper.selectByTextHashAndConfigCode(textHash, configCode);
|
|
ContentVector cached = pgContentVectorMapper.selectByTextHashAndConfigCode(textHash, configCode);
|
|
|
if (cached != null && StringUtils.hasText(cached.getEmbedding())) {
|
|
if (cached != null && StringUtils.hasText(cached.getEmbedding())) {
|
|
|
- return parseVectorString(cached.getEmbedding());
|
|
|
|
|
|
|
+ return VectorUtils.parseVectorString(cached.getEmbedding());
|
|
|
}
|
|
}
|
|
|
} catch (Exception e) {
|
|
} catch (Exception e) {
|
|
|
log.error("查询 text_hash 向量缓存失败,hash={}, configCode={}, error={}",
|
|
log.error("查询 text_hash 向量缓存失败,hash={}, configCode={}, error={}",
|
|
@@ -351,17 +233,16 @@ public class VectorizeServiceImpl implements VectorizeService {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
@Override
|
|
|
- public int batchSaveVectors(List<DeconstructContentVector> vectors) {
|
|
|
|
|
|
|
+ public int batchSaveVectors(List<ContentVector> vectors) {
|
|
|
if (CollectionUtils.isEmpty(vectors)) {
|
|
if (CollectionUtils.isEmpty(vectors)) {
|
|
|
return 0;
|
|
return 0;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
int count = 0;
|
|
int count = 0;
|
|
|
- for (DeconstructContentVector vector : vectors) {
|
|
|
|
|
|
|
+ for (ContentVector vector : vectors) {
|
|
|
try {
|
|
try {
|
|
|
- // 存储到 pgvector
|
|
|
|
|
- String embedding = vector.getVectorData();
|
|
|
|
|
- // vectorData 是 JSON 数组格式 "[0.1,0.2,...]",pgvector 也接受这种格式
|
|
|
|
|
|
|
+ // 存储到 pgvector,embedding 是 JSON 数组格式 "[0.1,0.2,...]"
|
|
|
|
|
+ String embedding = vector.getEmbedding();
|
|
|
pgContentVectorMapper.upsertWithEmbedding(
|
|
pgContentVectorMapper.upsertWithEmbedding(
|
|
|
vector.getContentId(),
|
|
vector.getContentId(),
|
|
|
vector.getTaskId(),
|
|
vector.getTaskId(),
|
|
@@ -385,80 +266,19 @@ public class VectorizeServiceImpl implements VectorizeService {
|
|
|
return count;
|
|
return count;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- /**
|
|
|
|
|
- * 根据 contentId 查询向量列表(从 pgvector 查询)
|
|
|
|
|
- */
|
|
|
|
|
@Override
|
|
@Override
|
|
|
- public List<DeconstructContentVector> getVectorsByContentId(Long contentId) {
|
|
|
|
|
- List<ContentVector> pgVectors = pgContentVectorMapper.selectByContentId(contentId);
|
|
|
|
|
- return convertToDeconstructVectors(pgVectors);
|
|
|
|
|
|
|
+ public List<ContentVector> getVectorsByContentId(Long contentId) {
|
|
|
|
|
+ return pgContentVectorMapper.selectByContentId(contentId);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
@Override
|
|
|
- public List<DeconstructContentVector> getVectorsByContentId(Long contentId, String configCode) {
|
|
|
|
|
- List<ContentVector> pgVectors = pgContentVectorMapper.selectByContentIdAndConfigCode(contentId, configCode);
|
|
|
|
|
- return convertToDeconstructVectors(pgVectors);
|
|
|
|
|
|
|
+ public List<ContentVector> getVectorsByContentId(Long contentId, String configCode) {
|
|
|
|
|
+ return pgContentVectorMapper.selectByContentIdAndConfigCode(contentId, configCode);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
@Override
|
|
|
- public List<DeconstructContentVector> getVectorsByField(Long contentId, String sourceField) {
|
|
|
|
|
- List<ContentVector> pgVectors = pgContentVectorMapper.selectByContentIdAndField(contentId, sourceField);
|
|
|
|
|
- return convertToDeconstructVectors(pgVectors);
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- /**
|
|
|
|
|
- * 将 pgvector ContentVector 转换为 DeconstructContentVector(兼容现有接口)
|
|
|
|
|
- */
|
|
|
|
|
- private List<DeconstructContentVector> convertToDeconstructVectors(List<ContentVector> pgVectors) {
|
|
|
|
|
- if (CollectionUtils.isEmpty(pgVectors)) {
|
|
|
|
|
- return new ArrayList<>();
|
|
|
|
|
- }
|
|
|
|
|
- return pgVectors.stream().map(pv -> {
|
|
|
|
|
- DeconstructContentVector dcv = new DeconstructContentVector();
|
|
|
|
|
- dcv.setId(pv.getId());
|
|
|
|
|
- dcv.setContentId(pv.getContentId());
|
|
|
|
|
- dcv.setTaskId(pv.getTaskId());
|
|
|
|
|
- dcv.setConfigCode(pv.getConfigCode());
|
|
|
|
|
- dcv.setSourceField(pv.getSourceField());
|
|
|
|
|
- dcv.setSourcePath(pv.getSourcePath());
|
|
|
|
|
- dcv.setTextHash(pv.getTextHash());
|
|
|
|
|
- dcv.setEmbeddingModel(pv.getEmbeddingModel());
|
|
|
|
|
- dcv.setSegmentIndex(pv.getSegmentIndex());
|
|
|
|
|
- dcv.setSegmentTotal(pv.getSegmentTotal());
|
|
|
|
|
- dcv.setSourceText(pv.getSourceText());
|
|
|
|
|
- // 将 pgvector 格式的 embedding 转为 JSON 数组格式的 vectorData
|
|
|
|
|
- if (StringUtils.hasText(pv.getEmbedding())) {
|
|
|
|
|
- dcv.setVectorData(pv.getEmbedding());
|
|
|
|
|
- }
|
|
|
|
|
- dcv.setCreateTime(pv.getCreatedAt());
|
|
|
|
|
- dcv.setUpdateTime(pv.getUpdatedAt());
|
|
|
|
|
- return dcv;
|
|
|
|
|
- }).collect(Collectors.toList());
|
|
|
|
|
|
|
+ public List<ContentVector> getVectorsByField(Long contentId, String sourceField) {
|
|
|
|
|
+ return pgContentVectorMapper.selectByContentIdAndField(contentId, sourceField);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- /**
|
|
|
|
|
- * 解析 pgvector 字符串为 List<Float>
|
|
|
|
|
- * 格式: "[0.1,0.2,...]" 或 pgvector 输出的 "[0.1,0.2,...]"
|
|
|
|
|
- */
|
|
|
|
|
- private List<Float> parseVectorString(String vectorStr) {
|
|
|
|
|
- if (vectorStr == null || vectorStr.isEmpty()) return null;
|
|
|
|
|
- try {
|
|
|
|
|
- String trimmed = vectorStr.trim();
|
|
|
|
|
- if (trimmed.startsWith("[")) {
|
|
|
|
|
- trimmed = trimmed.substring(1);
|
|
|
|
|
- }
|
|
|
|
|
- if (trimmed.endsWith("]")) {
|
|
|
|
|
- trimmed = trimmed.substring(0, trimmed.length() - 1);
|
|
|
|
|
- }
|
|
|
|
|
- String[] parts = trimmed.split(",");
|
|
|
|
|
- List<Float> result = new ArrayList<>(parts.length);
|
|
|
|
|
- for (String part : parts) {
|
|
|
|
|
- result.add(Float.parseFloat(part.trim()));
|
|
|
|
|
- }
|
|
|
|
|
- return result;
|
|
|
|
|
- } catch (Exception e) {
|
|
|
|
|
- log.error("向量字符串解析失败: {}", e.getMessage());
|
|
|
|
|
- return null;
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
}
|
|
}
|