qidao123.com技术社区-IT企服评测·应用市场

标题: 机器图纸文章标题搜索增强实现过程 [打印本页]

作者: 祗疼妳一个    时间: 2025-2-28 17:45
标题: 机器图纸文章标题搜索增强实现过程
1. 为什么需要使用搜索增强技术

  点击睁开
1.1 体验

微信小程序名称 极客共享 输入搜索内容 有没有土豆分拣机
  点击睁开

1.2 与传统全文检索(Elasticsearch)的对比

  点击睁开维度传统全文检索(Elasticsearch)搜索增强(基于语义向量)技术原理基于倒排索引和关键词匹配,依靠分词和词频统计(如 BM25)。基于大模型天生语义嵌入向量,使用向量相似度(如余弦相似度)匹配。语义理解仅匹配关键词,缺乏语义理解。理解标题和查询的语义,支持含糊匹配和同义词匹配。查询灵活性用户查询需与标题关键词高度一致,否则结果不准确。支持含糊查询和不同表述的匹配(如“土豆分拣机”匹配“马铃薯筛选机”)。专业术语处理依靠分词器,专业术语可能被错误切分(如“土豆分拣机”被切为“土豆”和“分拣机”)。通过预训练模型理解专业术语和同义词的语义,减少分词错误。结果相干性基于词频和位置排序,可能返回无关结果。基于语义相似度排序,结果更相干。实时性与性能倒排索引查询速度快,但语义匹配需额外插件(如 Elasticsearch KNN)。向量搜索需高效索引(如 RedisSearch),实时性稍逊但可优化。适用场景得当关键词明白、标题格式标准化的场景。得当标题复杂、查询含糊或需语义理解的场景。机器图纸标题搜索示例查询“土豆分拣机”,仅匹配标题中包罗“土豆分拣机”的图纸,遗漏“马铃薯筛选机”。查询“土豆分拣机”,可匹配语义相似的标题,如“马铃薯筛选机”,因为 AI 模型理解“土豆”和“马铃薯”、“分拣”和“筛选”是同义词。
1.3 搜索增强的含义

2. 系统架构设计

2.1 团体架构

2. 实现步骤

2.1 机器图纸标题向量天生与存储

2.1.1 准备机器图纸标题数据

  点击睁开

2.1.2 .NET Core 调用 Python API 天生向量

    Python向量天生范例
  1. from FlagEmbedding import FlagModel
  2. import pandas as pd
  3. import numpy as np
  4. from datasets import Dataset
  5. from scipy.spatial import distance
  6. import datetime
  7. import configparser
  8. import pymysql  
  9. model = None
  10. def getModel():
  11.     global model
  12.     if model is None:
  13.         model = FlagModel("./model",
  14.                     query_instruction_for_retrieval="Represent this sentence for searching relevant passages:",
  15.                     use_fp16=True)
  16.     return model
  17. #获取向量
  18. def getFlagEmbedding(title):
  19.     global model
  20.     model = getModel()
  21.     embedding = model.encode(title)
  22.     return embedding
  23.   
复制代码
   .NET Core调用天生接口(其实就是普通的api请求)
  1. /// <summary>
  2. /// 获取向量
  3. /// </summary>
  4. /// <param name="keyword"></param>
  5. /// <returns></returns>
  6. public async Task<double[]> GetFlagEmbedding(string keyword)
  7. {
  8.      var vector = new double[] { };
  9.      vector = null;
  10.      try
  11.      {
  12.          var req = new
  13.          {
  14.              action = "getFlagEmbedding",
  15.              keyword
  16.          };
  17.          var content = new StringContent(
  18.                         JsonSerializer.Serialize(req)
  19.                         , Encoding.UTF8, "application/json");
  20.          var response = await _client.PostAsync(ConfigHelp.FlagSerachUrl, content);
  21.          if (response.IsSuccessStatusCode)
  22.          {
  23.              var result = await response.Content.ReadAsStringAsync();
  24.              var data = JsonSerializer.Deserialize<GetFlagEmbeddingRoot>(result);
  25.              if (data.op)
  26.              {
  27.                  vector = data.msg.Split(',').Select(double.Parse).ToArray();
  28.              }
  29.          }
  30.      }
  31.      catch (Exception ex)
  32.      {
  33.          LogUtils.Error("GetFlagEmbedding ", ex);
  34.      }
  35.      return vector;
  36. }
复制代码
2.1.3 存储向量到 Redis

    搜索数据
  1.    public class RedisVectorHelp
  2.    {
  3.        private readonly IDatabase _db;
  4.        private string _freefix;
  5.        private string _indexName;
  6.        private SearchCommands ft;
  7.        public RedisVectorHelp(string freefix,string redisConnectionString,int dbNum=0)
  8.        {
  9.            var redis = ConnectionMultiplexer.Connect(redisConnectionString);
  10.            _db = redis.GetDatabase(dbNum);
  11.            _freefix = freefix;
  12.            _indexName = _freefix + "_index";
  13.            ft = new SearchCommands(_db, null);
  14.        }
  15.        /// <summary>
  16.        /// 创建索引
  17.        /// </summary>
  18.        public void CreateFt()
  19.        {
  20.            var list = ft._List();
  21.            var indexList = list.Select(result => result.ToString()).ToArray();
  22.            //判断是否存在索引
  23.            if (indexList.Contains(_indexName))
  24.            {
  25.                Console.WriteLine("Index already exists.");
  26.                return;
  27.            }
  28.            ft.Create(_indexName,
  29. new FTCreateParams()
  30.      .On(IndexDataType.HASH)
  31.      .Prefix(_freefix + ":"),
  32. new Schema()
  33.      .AddTextField("id")
  34.      .AddVectorField("vector",
  35.      VectorField.VectorAlgo.FLAT,
  36.          new Dictionary<string, object>
  37.          {
  38.              ["TYPE"] = "FLOAT32",
  39.              ["DIM"] = 1024,
  40.              ["DISTANCE_METRIC"] = "COSINE"
  41.          })
  42.      );
  43.        }
  44.        /// <summary>
  45.        /// 存储向量
  46.        /// </summary>
  47.        /// <param name="id"></param>
  48.        /// <param name="vector"></param>
  49.        public void StoreVectorData(string id, float[] vector)
  50.        {
  51.            // 构造键名
  52.            var key = $"{_freefix}:{id}";
  53.            VectorDom dom = new VectorDom
  54.            {
  55.                id = id,
  56.                vector = vector
  57.            };
  58.            byte[] vectorBinary = vector.SelectMany(f => BitConverter.GetBytes(f)).ToArray();
  59.            _db.HashSet(key, "id", dom.id);
  60.            _db.HashSet(key, "vector", vectorBinary);
  61.        }
  62.        /// <summary>
  63.        /// 向量搜索
  64.        /// </summary>
  65.        /// <param name="queryVector"></param>
  66.        /// <param name="topK"></param>
  67.        public List<string> SearchSimilarVectors(float[] queryVector, int topK = 50)
  68.        {
  69.            byte[] vectorQueryBinary = queryVector.SelectMany(f => BitConverter.GetBytes(f)).ToArray();
  70.            //十六进制字符串
  71.            //string vectorQueryBinaryStr = BitConverter.ToString(vectorQueryBinary).Replace("-", "");
  72.            Query q = new Query($"*=>[KNN {topK} @vector $vec as score]");
  73.            q.SortBy = "score";
  74.            q.AddParam("vec", vectorQueryBinary);
  75.            q.ReturnFields("id", "vector");
  76.            q.Limit(0, topK);
  77.            q.Dialect(2);
  78.            var obj = ft.Search(_indexName, q);
  79.            var docList = obj.Documents;
  80.            var list = new List<string>();
  81.            foreach (var doc in docList)
  82.            {
  83.                list.Add(doc["id"]);
  84.            }
  85.            return list;
  86.        }
  87.    }
  88.    public class VectorDom
  89.    {
  90.        public string id { get; set; }
  91.        public float[] vector { get; set; }
  92.    }
复制代码
2.2.1 使用查询向量在 Redis 中搜索

    RedisVector核心操作类
  1. var searchVector = await GetFlagEmbedding(keyword);
  2. if (searchVector != null)
  3. {
  4.      var queryVector = Array.ConvertAll(searchVector, x => (float)x);
  5.      var temp = bykcsjRVHelp.SearchSimilarVectors(queryVector, 30);
  6.      foreach (var id in temp)
  7.      {
  8.          if (!ids.Contains(id))
  9.          {
  10.              ids.Add(id);
  11.          }
  12.      }
  13. }
复制代码
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。




欢迎光临 qidao123.com技术社区-IT企服评测·应用市场 (https://dis.qidao123.com/) Powered by Discuz! X3.4