elkan K-Means算法

news/2025/2/25 21:25:58

简介

在计算向量相似度时,常用 近似最近邻(ANN, Approximate Nearest Neighbor)算法 来加速查询向量的搜索。其中,较为知名的 ANN 算法包括 HNSW、Ivfflat、Ivfpq 和 Ivfsq。在 IVF(倒排索引,Inverted File Index) 类型的算法中,Elkan K-Means 算法是较为经典的方法之一,并被广泛用于向量聚类和索引构建。

在 PostgreSQL 中,pgvector 插件提供了对向量数据的索引与搜索支持,而 Elkan K-Means 算法正是其中用于优化 IVF 聚类过程的关键技术。接下来,我们将深入解析 Elkan K-Means 算法的具体执行流程。

算法详情

C语言编写的完整代码过程(其中的宏和其他的内容暂不解释,主要讲解代码逻辑):

static void
ElkanKmeans(Relation index, VectorArray samples, VectorArray centers, const IvfTypeInfo * typeInfo)
{
   
	FmgrInfo   *procinfo;
	FmgrInfo   *normprocinfo;
	Oid			collation;
	int			dimensions = centers->dim;
	int			numCenters = centers->maxlen;
	int			numSamples = samples->length;
	VectorArray newCenters;
	float	   *agg;
	int		   *centerCounts;
	int		   *closestCenters;
	float	   *lowerBound;
	float	   *upperBound;
	float	   *s;
	float	   *halfcdist;
	float	   *newcdist;

	/* Calculate allocation sizes */
	Size		samplesSize = VECTOR_ARRAY_SIZE(samples->maxlen, samples->itemsize);
	Size		centersSize = VECTOR_ARRAY_SIZE(centers->maxlen, centers->itemsize);
	Size		newCentersSize = VECTOR_ARRAY_SIZE(numCenters, centers->itemsize);
	Size		aggSize = sizeof(float) * (int64) numCenters * dimensions;
	Size		centerCountsSize = sizeof(int) * numCenters;
	Size		closestCentersSize = sizeof(int) * numSamples;
	Size		lowerBoundSize = sizeof(float) * numSamples * numCenters;
	Size		upperBoundSize = sizeof(float) * numSamples;
	Size		sSize = sizeof(float) * numCenters;
	Size		halfcdistSize = sizeof(float) * numCenters * numCenters;
	Size		newcdistSize = sizeof(float) * numCenters;

	/* Calculate total size */
	Size		totalSize = samplesSize + centersSize + newCentersSize + aggSize + centerCountsSize + closestCentersSize + lowerBoundSize + upperBoundSize + sSize + halfcdistSize + newcdistSize;

	/* Check memory requirements */
	/* Add one to error message to ceil */
	if (totalSize > (Size) maintenance_work_mem * 1024L)
		ereport(ERROR,
				(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
				 errmsg("memory required is %zu MB, maintenance_work_mem is %d MB",
						totalSize / (1024 * 1024) + 1, maintenance_work_mem / 1024)));

	/* Ensure indexing does not overflow */
	if (numCenters * numCenters > INT_MAX)
		elog(ERROR, "Indexing overflow detected. Please report a bug.");

	/* Set support functions */
	procinfo = index_getprocinfo(index, 1, IVF_KMEANS_DISTANCE_PROC);
	normprocinfo = IvfOptionalProcInfo(index, IVF_KMEANS_NORM_PROC);
	collation = index->rd_indcollation[0];

	/* Allocate space */
	/* Use float instead of double to save memory */
	agg = palloc(aggSize);
	centerCounts = palloc(centerCountsSize);
	closestCenters = palloc(closestCentersSize);
	lowerBound = palloc_extended(lowerBoundSize, MCXT_ALLOC_HUGE);
	upperBound = palloc(upperBoundSize);
	s = palloc(sSize);
	halfcdist = palloc_extended(halfcdistSize, MCXT_ALLOC_HUGE);
	newcdist = palloc(newcdistSize);

	/* Initialize new centers */
	newCenters = VectorArrayInit(numCenters, dimensions, centers->itemsize);
	newCenters->length = numCenters;

#ifdef IVFFLAT_MEMORY
	ShowMemoryUsage(MemoryContextGetParent(CurrentMemoryContext));
#elif defined IVFPQ_MEMORY	
	ShowMemoryUsage(MemoryContextGetParent(CurrentMemoryContext));
#endif

	/* Pick initial centers */
	InitCenters(index, samples, centers, lowerBound);

	/* Assign each x to its closest initial center c(x) = argmin d(x,c) */
	for (int64 j = 0; j < numSamples; j++)
	{
   
		float		minDistance = FLT_MAX;
		int			closestCenter = 0;

		/* Find closest center */
		for (int64 k = 0; k < numCenters; k++)
		{
   
			/* TODO Use Lemma 1 in k-means++ initialization */
			float		distance = lowerBound[j * numCenters + k];

			if (distance < minDistance)
			{
   
				minDistance = distance;
				closestCenter = k;
			}
		}

		upperBound[j] = minDistance;
		closestCenters[j] = closestCenter;
	}

	/* Give 500 iterations to converge */
	for (int iteration = 0; iteration < 500; iteration++)
	{
   
		int			changes = 0;
		bool		rjreset;

		/* Can take a while, so ensure we can interrupt */
		CHECK_FOR_INTERRUPTS();

		/* Step 1: For all centers, compute distance */
		for (int64 j = 0; j < numCenters; j++)
		{
   
			Datum		vec = PointerGetDatum(VectorArrayGet(centers, j));

			for (int64 k = j + 1; k < numCenters; k++)
			{
   
				float		distance = 0.5 * DatumGetFloat8(FunctionCall2Coll(procinfo, collation, vec, PointerGetDatum(VectorArrayGet(centers, k))));

				halfcdist[j * numCenters + k] = distance;
				halfcdist[k * numCenters + j] = distance;
			}
		}

		/* For all centers c, compute s(c) */
		for (int64 j = 0; j < numCenters; j++)
		{
   
			float		minDistance = FLT_MAX;

			for (int64 k = 0; k < numCenters; k++)
			{
   
				

http://www.niftyadmin.cn/n/5865955.html

相关文章

开源RAG主流框架有哪些?如何选型?

开源RAG主流框架有哪些?如何选型? 一、开源RAG框架全景图 (一)核心框架类型对比 类型典型工具技术特征适用场景传统RAGLangChain, Haystack线性流程(检索→生成)通用问答、知识库检索增强型RAGRAGFlow, AutoRAG支持重排序、多路召回优化高精度问答、复杂文档处理轻量级…

为什么 JSON 不能序列化 set

为什么 JSON 不能序列化 set JSON&#xff08;JavaScript Object Notation&#xff09;作为一种广泛使用的数据交换格式&#xff0c;虽然功能强大&#xff0c;但它无法直接序列化 set 类型。本文将从设计原理、实现限制和实际应用角度&#xff0c;探讨这一现象的原因及解决方案…

Redis——用户签到BitMap,UV统计

目录 BitMap 使用场景 1. 用户签到系统 2. 用户行为标记 3. 布隆过滤器&#xff08;Bloom Filter&#xff09; BitMap介绍 Redis中的使用 Redis功能示例 添加&#xff1a; 获取&#xff1a; 批量获取&#xff1a; java中实现 统计本月连续签到次数 UV统计 UV 统计…

架构师论文《论湖仓一体架构及其应用》

软考论文-系统架构设计师 摘要 作为某省级商业银行数据中台建设项目技术负责人&#xff0c;我在2020年主导完成了从传统数据仓库向湖仓一体架构的转型。针对日益增长的支付流水、用户行为埋点及信贷审核影像文件等多模态数据处理需求&#xff0c;原有系统存在存储成本激增、实…

部署若依微服务遇到的坑

一、用Windows部署nacos 1、启动失败&#xff0c;因为nacos默认开启为器群模式。单体需要加上图下代码 2、nacos配置内置MySQL时需要执行config文件夹下的SQL文件 3、springboot启动报错 java.nio.charset.MalformedInputException: Input length 1或Input length 2-CSDN博…

C#中开发OCR应用时,以下是一些推荐的开源库和工具

在C#中开发OCR应用时&#xff0c;以下是一些推荐的开源库和工具&#xff0c;以及它们的简要使用指南&#xff1a; 1. Tesseract OCR (最主流推荐) 简介: Google 开源的OCR引擎&#xff0c;支持多语言&#xff0c;历史悠久且社区活跃。NuGet包: Tesseract (纯C#封装) 优点: 完全…

【前端】Axios AJAX Fetch

不定期更新&#xff0c;建议关注收藏点赞。 目录 AxiosAJAX Axios axios 是一个基于 Promise 的 JavaScript HTTP 客户端&#xff0c;用于浏览器和 Node.js 中发送 HTTP 请求。它提供了一个简单的 API 来发起请求&#xff0c;并处理请求的结果。axios 主要用于与服务器进行数据…

一周学会Flask3 Python Web开发-Jinja2模板访问对象

锋哥原创的Flask3 Python Web开发 Flask3视频教程&#xff1a; 2025版 Flask3 Python web开发 视频教程(无废话版) 玩命更新中~_哔哩哔哩_bilibili 如果渲染模板传的是对象&#xff0c;如果如何来访问呢&#xff1f; 我们看下下面示例&#xff1a; 定义一个Student类 cla…