MoreRSS

site iconafoo | 王福强修改

连续创业者,20多年互联网与金融技术经验,前阿里巴巴高级技术专家,现福强科技CEO,分享技术、管理、商业和AI知识。
请复制 RSS 到你的阅读器,或快速订阅到 :

Inoreader Feedly Follow Feedbin Local Reader

afoo | 王福强的 RSS 预览

KVectors向量数据库IVF索引,这测试结果我自己都想不到…

2025-09-27 00:00:00

KVectors向量数据库IVF索引,这测试结果我自己都想不到… -王福强的个人博客:一个架构士的思考与沉淀

KVectors向量数据库IVF索引,这测试结果我自己都想不到…

王福强

2025-09-27


测试数据集是Sift的100万向量数据, 向量维度是128维。

第一版的数据先作为基准,大家先有个感性对标:

从Sift的这100万向量数据集中查询一万条向量,一共用时159042毫秒(ms), 平均15.9毫秒, 跟KVectors里提供的HNSW+DiskANN版本查询性能相比,差八九毫秒,不过,也还不错,因为我第一版并没有严格按照IVF索引的语义进行的设计和实现,即向量数据我没有全都搬到内存里存放。

所以,从这角度来说,IO层面应该还有很大的提升空间。

于是,我就在重构完KVectors第三个版本的整体设计与实现之后,为向量存储新增了 loadAllVectorsIntoMemory 这个选项,并把它的默认值设置成了true,毕竟,现在生产服务器的内存轻轻松松就能搞定百万级别的向量数据存储。

搞定之后, 下面是几次粗略测试的结果截图(粗略测试是因为,我只是在2019年的老Intel MacbookPro上跑的这个测试):

一开始我没细看,以为省了几毫秒,细看发现, 这tmd平均不到2毫秒啊!!!

1.1毫秒到1.3毫秒…

我都没想到有这么惊喜,那看来HNSW+DiskANN版本也有很大提升空间咯~

后来,为了再看看没有构建IVF索引之前查询同样数据会是怎么样一个结果,我又跑了下(当然,还是全量数据放内存):

性能急降,平均单次查询直接给干到了230毫秒, 😂

所以,IVF索引功不可没啊!

另外,感谢王总预约了下个月的新培训,感兴趣的企业也欢迎预约哟~




「福强私学」来一个?

「福强私学」, 一部沉淀了个人成长、技术与架构、组织与管理以及商业上的方法与心法的百科全书。

footer img for kb.afoo.me

开天窗,拉认知,订阅「福报」,即刻拥有自己的全模态人工智能。

订阅「福报」
Copyright © 王福强个人版权所有 - Since 2004 (Everything is homebrewed with Pandoc and Markdown, little Scala also included.)

使用KVectors向量数据库构建以图搜图应用

2025-09-20 00:00:00

使用KVectors向量数据库构建以图搜图应用 -王福强的个人博客:一个架构士的思考与沉淀

使用KVectors向量数据库构建以图搜图应用

王福强

2025-09-20


以图搜图是电商平台上很常见的用户需求,

今天,我们尝试用最轻量级的方式,

为大家演示如何用KVector向量数据库构建一个以图搜图应用。

KVectors 支持三层访问模式:

我们选择最内核的方式,即以Library/类库的方式使用KVectors,因为这可以帮助我们构建最内聚的应用集成度, 安装与部署和使用对用户来说都更为友好。

整个以图搜图的应用流程很简单,主要两个方向:

  1. 上传图片到图片存储到时候(比如云上的对象存储,或者其他第三方图床), 我们会使用图像Embedding模型对上传的图片进行embedding操作, 然后将获得的图片对应的embedding(即向量)存入KVectors向量数据库。 当然,图片的上传与计算图像Embedding可以是并行的(也可以串行),这个根据应用的时延(Latency)要求决定就可以了。
  2. 搜索图像的时候,用户提交一个图像,我们依然是先针对这个图像进行Embedding,获得对应的embedding向量之后,拿着它去KVectors向量数据库中去搜索相似的embeddings,然后将相似的embeddings作为搜索结果,并根据其对应的元信息(metadata)获取对应的原始图像信息(比如存储地址),然后再展示给用户,从而完成整体的以图搜图闭环功能。

既然本次我们主要专注在轻量与集成度上,图像的embedding模型我们选择了一个比较老的小模型:MobileNetV2,相对于最新的VL模型或者CLIP模型,效果上可能不是最好的,但完成基础的以图搜图能力还是没有问题的(无非搜索的时候threshold要降低下标准🤪)

图像embedding与存入KVectors的代码大体如下:

    public float[] embed(String imagePath) throws IOException, OrtException {
        float[] preprocessedData = MobileNetV2ImagePreprocessor.preprocessImage(imagePath);
        
        long[] inputShape = {1, 3, 224, 224};
        
        OnnxTensor inputTensor = OnnxTensor.createTensor(environment, FloatBuffer.wrap(preprocessedData), inputShape);

        try (OrtSession.Result result = session.run(Collections.singletonMap("pixel_values", inputTensor))) {
            return ImageEmbeddingExtractor.extractWithGlobalAvgPooling(result);
        }
    }
    val collectionOption = kdb.getCollection("ImageSearchVectorCollectionName")
    if (collectionOption.isDefined) {
      val vectorCollection = collectionOption.get
      vectorCollection.add(VectorRecord(vector, VectorMetadata(url, None)))
    } else {
      throw new IllegalStateException(s"no vector collection found in kvectors db at ${kdb.dataDir}")
    }

kdb即KVectors向量数据库的对象引用,它的初始化也很简单:

val kdb = new KVectors(new File(keeboxDir, "kvectors")) // <<< 主要这一行
Shutdowns.addShutdownRunnable(() => Cleaner.closeWithLog(kdb)) // 这行是为了擦屁股,在程序关闭后清理KVectors的相应资源

KVectors的设计包含向量数据库和向量集合(KVectorCollection)两级概念,一个KVectors向量数据库可以包含很多向量集合(KVectorCollection), 向量最终存入相应的向量集合(KVectorCollection),比如上面是用一个假名字ImageSearchVectorCollectionName作为向量集合的名字(这个参数你可以根据情况取)获得对应的向量集合对象引用,然后向其中添加向量。(向量集合预先已经在其他地方创建)

最后就是, VectorRecord的第一个参数vector就是前面embed方法返回的结果。 至于文件上传的代码,就不演示了,根据选用的公有云不同而API不同。

当图像的embedding存入KVectors向量数据库之后, 我们就可以针对他们进行相似度搜索了,来了一个图像,我们依然对其进行embed调用获得图像对应的embedding向量, 然后根据获得的这个embedding向量到KVectors向量数据库中查询:

      val embeddingVector = imageEmbeddingExecutor.embed(tmpFile.getAbsolutePath)

      val collectionOption = kdb.getCollection("ImageSearchVectorCollectionName")
      if (collectionOption.isDefined) {
        val ab = new ArrayBuffer[SearchResult]()
        logger.info(s"start search with topK=${topK}, threshold=${threshold} ..")
        collectionOption.get.query(embeddingVector, topK = topK, threshold = threshold).forEach(vectorResult => {
          val score = vectorResult.score.get
          val url = vectorResult.meta.getString("rid")
          logger.info(s"found image meet threshold at ${url} with score=${score}")
          ab.append(SearchResult(url, score))
        })
        ab.toArray
      } else {
        Array.empty
      }

KVectors的设计中要求每个向量存入之前都要有一个 relation id 与之对应,在以图搜图这个场景中,我们使用图像的url作为这个relation id,即meta元信息中的rid的值就是图像的url, 这个值我们将用来获取图像展示给用户。(同时,用户点击图像的时候,会打开对应图像)

搜索的时候,除了图像的embedding向量, 还有两个参数要跟大家说明下:

  1. topK,这个参数主要控制搜索结果的数量,比如返回11条相似性结果或者50条,这个根据应用需求决定就好了;
  2. threshold, 这个参数控制相似性匹配的标准,取值一般在0到1之间,假如Embedding模型质量很好,一般设置0.8以上就可以了,我们选择的 MobileNetV2 模型因为年代久远而且参数量比较少,有些时候效果不理想,所以,偶尔需要降低threshold的值,比如降低到0.6,0.7这样。

下面是以图搜图的一个JavaFX应用的简单界面,供大家参考视觉效果:

用户通过拖拽或者剪切板粘贴要搜索的图像到目标区域(即Drop File Here图标位置),点击Search就可以获得搜索结果了。

当然,点击搜索之前,也可以调整topK和threshold两个参数的默认值。

至此,一个基于KVectors向量数据库的以图搜图应用就算构建完成了,是不是很简单?

除了以图搜图场景,KVectors向量数据库还可以在产品推荐、客服知识库、传统与各种RAG变种等不同场景发挥同样强大的作用。

海量向量数据集中搜索时延 6.8 毫秒,可不是谁家的向量数据库都能达到的指标哟 🤪

同时欢迎各大企业预定与选购KVectors向量数据库,让自己在AI时代划出美丽的第二增长曲线。😎




「福强私学」来一个?

「福强私学」, 一部沉淀了个人成长、技术与架构、组织与管理以及商业上的方法与心法的百科全书。

footer img for kb.afoo.me

开天窗,拉认知,订阅「福报」,即刻拥有自己的全模态人工智能。

订阅「福报」
Copyright © 王福强个人版权所有 - Since 2004 (Everything is homebrewed with Pandoc and Markdown, little Scala also included.)

Java Web框架历史演化: 看这一篇就够了 (Java web frameworks in different ages)

2025-09-17 00:00:00

Java Web框架历史演化: 看这一篇就够了 (Java web frameworks in different ages) -王福强的个人博客:一个架构士的思考与沉淀

Java Web框架历史演化: 看这一篇就够了 (Java web frameworks in different ages)

王福强

2025-09-17


今天看到一海外老哥发了这么条短文字:

You can learn 100 JavaScript frameworks…

or you can learn Java and Spring once, and it’ll pay you back for years. 💚

虽然JavaScript作为前端事实上的语言带动了前端JS框架的蓬勃发展,包括但不限于Jquery,React,Vue,Svelte 1, Angular,HTMX2, etc

但Java其实也不是只有Spring一家,只不过,Spring确实一家独大了20十多年,哈哈哈哈

今天帮大家梳理下Java这片国土上的Web frameworks的发展与演化…

早在2003年之前笔者还没本科毕业那会儿,J2EE一家独大,笨重的EJB/EJB2还得依托JBuilder才能省点儿开发的劲儿,那时候最流行的web framework叫webwork,struts那时候还是1.x时代。

后来(此时想起刘若英的歌声)…

除了几个怪咖, Google 的 GWT 和 Sun 自己搞的JSF, GWT还好, Gmail就是用它搞出来的,当年也是轰动一时, 这JSF嘛,就雷声大雨点儿小了…

再后来, 咚咚咚咚,Spring开始风风火火了,SpringMVC也一并跃入Web开发主流…

(这时候有没有想起哥的传说?🤣)

Spring称霸Java开发界20多年之后,出来了新生代Web frameworks

他们的代表是:

  1. Quarkus
  2. Micronaut

他们的主要特征是利用了Java语言以及Java虚拟机的新特性,比如GraalVM以及Project Layden的AoT特性

而且,除了Java主航道,Scala/Groovy/Clojure/Kotlin等旁支也有自己的web frameworks演化,其中比较有名的有:

  1. play framework (scala)
  2. grails (groovy)

所以,综合来看,Java平台上的web frameworks也不少,但也不得不承认,Spring依然是主流🤣

最后,作者自己还写了个自己用的小web framework叫 Kate以及基于上扩展的keewebx, 当然,纯粹玩票性质,只是个人项目用用。


  1. Simple Svelte,https://afoo.me/books.html↩︎

  2. HTMX揭秘, https://afoo.me/books.html↩︎




「福强私学」来一个?

「福强私学」, 一部沉淀了个人成长、技术与架构、组织与管理以及商业上的方法与心法的百科全书。

footer img for kb.afoo.me

开天窗,拉认知,订阅「福报」,即刻拥有自己的全模态人工智能。

订阅「福报」
Copyright © 王福强个人版权所有 - Since 2004 (Everything is homebrewed with Pandoc and Markdown, little Scala also included.)

Java 25 尝鲜体验

2025-09-17 00:00:00

Java 25 尝鲜体验 -王福强的个人博客:一个架构士的思考与沉淀

Java 25 尝鲜体验

王福强

2025-09-17


Java 25 出来啦~

把 JavaFX相关的几个项目先直接升级到了Java 25,没任何错误需要修复,相当丝滑,最主要的是,换完jdk,重新打包后,keeboxfx的安装包从919+M降到了715.6M🤣 ,就一个字,帅,三个字,干得漂亮

顺便把 KVectors 也一并升了:

LuckyJohn💫 ➜  kVectors git:(master)  git ci -m "bump up java to 25"
[master 982663f] bump up java to 25
 2 files changed, 27 insertions(+), 2 deletions(-)

有小兄弟说我追新,哈哈哈,只要这个新带来的是好的,就应该追。

什么都不做,只要升级单一依赖就能带来性能和效率上的绝大提升,干嘛不追?🤣

Java 25 这次发布主要包含了如下几个大的JEP特性:

  • JEP 470 PEM Encodings of Cryptographic Objects // 这个好
  • JEP 502 Stable Values // 线程安全的lazy init, 有点儿loading cache那种API设计风格。
  • JEP 503 Remove the 32-bit x86 Port
  • JEP 505 Structured Concurrency // // 这个可以
  • JEP 506 Scoped Values // virtual threads的完美搭档
  • JEP 507 Primitive Types in Patterns, instanceof, and switch // java语法特性
  • JEP 508 Vector API (Tenth Incubator)// 这阵子个人关注最多的JEP
  • JEP 509 JFR CPU-Time Profiling // JFR打头儿的都是技术保障部的事儿,性能与稳定性🤣
  • JEP 510 Key Derivation Function API // 这个也好, 量子计算来了也不怕。
  • JEP 511 Module Import Declarations // jpms带来的那啥
  • JEP 512 Compact Source Files and Instance Main Methods // java 写脚本
  • JEP 513 Flexible Constructor Bodies // 继承上的改进,super()和this()不用非得在方法第一行了。
  • JEP 514 Ahead-of-Time Command-Line Ergonomics // AOT 打头儿的估计都从graalvm剥离出来的?Project Leyden vs. graalvm
  • JEP 515 Ahead-of-Time Method Profiling
  • JEP 518 JFR Cooperative Sampling
  • JEP 519 Compact Object Headers // 省内存,$ java -XX:+UseCompactObjectHeaders …
  • JEP 520 JFR Method Timing & Tracing
  • JEP 521 Generational Shenandoah // 垃圾回收(gc)上的改进

当然,还有成千的微小改进和bug修复,这一般都一笔带过,但积攒多了带来的也是质变。

每个特性详细介绍,这篇文章我觉得写的挺好(下面表格也是整理自这篇文章),感兴趣的同学可以看看:https://hanno.codes/2025/09/16/heres-java-25/

JEP Title Status Project Feature Type Changes since Java 24
(#jep-470-pem-encodings-of-cryptographic-objects-preview) PEM Encodings of Cryptographic Objects Preview Security Libs Security New feature
(#jep-502-stable-values-preview) Stable Values Preview Core Libs New API New feature
(#jep-503-remove-the-32-bit-x86-port) Remove the 32-bit x86 Port HotSpot Deprecation Removal
(#jep-505-structured-concurrency-fifth-preview) Structured Concurrency Fifth Preview Loom Concurrency Major
(#jep-506-scoped-values) Scoped Values Loom Concurrency Minor
(#jep-507-primitive-types-in-patterns-instanceof-and-switch-third-preview) Primitive Types in Patterns, instanceof, and switch Third Preview Amber Language None
(#jep-508-vector-api-tenth-incubator) Vector API Tenth Incubator Panama New API Minor
(#jep-509-jfr-cpu-time-profiling-experimental) JFR CPU-Time Profiling Experimental HotSpot / JFR Profiling New feature
(#jep-510-key-derivation-function-api) Key Derivation Function API Security Libs Security None
(#jep-511-module-import-declarations) Module Import Declarations Amber Language None
(#jep-512-compact-source-files-and-instance-main-methods) Compact Source Files and Instance Main Methods Amber Language Major
(#jep-513-flexible-constructor-bodies) Flexible Constructor Bodies Amber Language None
(#jep-514-ahead-of-time-command-line-ergonomics) Ahead-of-Time Command-Line Ergonomics Leyden Performance New feature
(#jep-515-ahead-of-time-method-profiling) Ahead-of-Time Method Profiling Leyden Performance New feature
(#jep-518-jfr-cooperative-sampling) JFR Cooperative Sampling HotSpot / JFR Profiling New feature
(#jep-519-compact-object-headers) Compact Object Headers HotSpot Performance None
(#jep-520-jfr-method-timing–tracing) JFR Method Timing & Tracing HotSpot / JFR Profiling New feature
(#jep-521-generational-shenandoah) Generational Shenandoah HotSpot / GC Performance Stability and performance improvements

NOTE

JEP life stages: incubation -> preview -> finalized.




「福强私学」来一个?

「福强私学」, 一部沉淀了个人成长、技术与架构、组织与管理以及商业上的方法与心法的百科全书。

footer img for kb.afoo.me

开天窗,拉认知,订阅「福报」,即刻拥有自己的全模态人工智能。

订阅「福报」
Copyright © 王福强个人版权所有 - Since 2004 (Everything is homebrewed with Pandoc and Markdown, little Scala also included.)

瞧不起知识产权的三个典型人物

2025-09-14 00:00:00

瞧不起知识产权的三个典型人物 -王福强的个人博客:一个架构士的思考与沉淀

瞧不起知识产权的三个典型人物

王福强

2025-09-14


乔布斯

乔布斯在某个大学还是什么场合讲香蕉那个段子 1,相信大家都看到过吧?

瞧不起咨询公司,不就是瞧不起知识产权嘛

问题是,咨询公司也是公司,咨询公司也分段位啊,橘子非得跟香蕉比啊?

柏拉图

几千年前柏拉图也瞧不上知识产权,说画家比木匠差两个档次。

但今天大家也看到了, 木匠作品挣大钱的有,不怎么挣钱的也有,画家也是,要比也得顶级对顶级比吧?

他可能就是觉得实物才算创造?🤪

杨吉光

当然了,说到不尊重知识产权的,最典型的就是《插翅难逃》里的杨吉光了

天天跟张世豪要五五分账,到死也没分成…

所以,江湖上才会流传:

五五分账杨吉光

知识产权张世豪

🤣🤣🤣


  1. 之前也谈到过这个话题↩︎




「福强私学」来一个?

「福强私学」, 一部沉淀了个人成长、技术与架构、组织与管理以及商业上的方法与心法的百科全书。

footer img for kb.afoo.me

开天窗,拉认知,订阅「福报」,即刻拥有自己的全模态人工智能。

订阅「福报」
Copyright © 王福强个人版权所有 - Since 2004 (Everything is homebrewed with Pandoc and Markdown, little Scala also included.)

KVectors 压缩向量搜索重要跑通了…

2025-09-13 00:00:00

KVectors 压缩向量搜索重要跑通了… -王福强的个人博客:一个架构士的思考与沉淀

KVectors 压缩向量搜索重要跑通了…

王福强

2025-09-13


blocking了半个月,终于通过读原始代码解决了KVectors绕不过去的一个大坑…

之前总是segment fault, 这错误让我这种对操作系统和硬件比较打怵的人来说,有点儿抓瞎😂

不过,这个问题不解决,一直block在那儿也不行,给依赖类库也提交了issue,作者没屌我,可能觉得问题太小儿科,或者海外工作节奏比较闲适? 🤪

问AI其实更无解,最后只能自己啃依赖库的源代码,昨天发现苗头儿,今天修改验证后,一切OK了 ✅

用Sift的数据集做的测试(128维向量)

从100万条向量数据中查询1万条简单跑了下,数据看起来还可以, 平均6.3毫秒

而且是在2019年的老 MacbookPro 上跑的…

#KVectors #向量数据库




「福强私学」来一个?

「福强私学」, 一部沉淀了个人成长、技术与架构、组织与管理以及商业上的方法与心法的百科全书。

footer img for kb.afoo.me

开天窗,拉认知,订阅「福报」,即刻拥有自己的全模态人工智能。

订阅「福报」
Copyright © 王福强个人版权所有 - Since 2004 (Everything is homebrewed with Pandoc and Markdown, little Scala also included.)