2
2
3
3
---
4
4
layout: post
5
- title: "向量数据库 "
5
+ title: "向量搜索 "
6
6
date: 2024-05-21 01:08:48 +0800
7
7
categories: elasticsearch milvus
8
8
tags: elasticsearch milvus
@@ -14,96 +14,22 @@ tags: elasticsearch milvus
14
14
{: toc }
15
15
16
16
# 向量相似度
17
- 在最开始,向量相似度的相关问题我是通过ChatGPT来整理的。
18
-
19
- ## knn
20
- [ knn(k-nearest neighbor,k近邻)算法] ( https://www.elastic.co/what-is/knn/ ) ,用来求不同点之间的距离。有多种距离计算方法:
21
- - Euclidean distance:欧几里得距离,x + y
22
- - Manhattan distance:曼哈顿距离,也是我们常用的坐标系中的距离,是x^2 + y^2再开根号;
23
- - 还有其他距离;
24
-
25
- 余弦则可以用来计算两个向量的相似性,也就是人们常说的“小xx”,和上述距离相比,区别大概是:
26
- - 距离是两个人绝对实力的差距,比如梅西和c罗实力接近,他们的曼哈顿距离接近;
27
- - 相似性是两个人的技术特征相似,比如“小梅西”指一个人技术风格和梅西比较像,但是实力可能相去甚远;
28
-
29
- 余弦相似度通常用于衡量两个向量之间的相似度,它在文本分类、推荐系统等领域有广泛应用。
30
-
31
- 在文本分类中,我们通常使用向量空间模型(Vector Space Model)来表示文本,将每个文档表示为一个向量,其中每个维度表示一个词语。这些向量可以使用余弦相似度来计算它们之间的相似度,从而进行分类。
32
-
33
- 在推荐系统中,我们通常使用协同过滤算法来推荐物品。协同过滤算法需要计算用户之间的相似度,以确定哪些用户具有相似的兴趣。在这种情况下,我们通常使用余弦相似度来计算用户之间的相似度,因为它可以很好地衡量它们之间的夹角,即它们之间的兴趣相似度。
34
-
35
- 因此,** 当我们需要衡量两个向量之间的相似度时,余弦相似度通常是一个很好的选择。而在需要考虑绝对差异的情况下,如KNN算法中,我们通常使用欧几里得距离来计算点之间的距离** 。
36
-
37
- ## 编码方式
38
- Elasticsearch的KNN是指基于k最近邻算法的搜索功能。它允许用户在Elasticsearch中存储和搜索向量数据,并使用KNN算法来查找与查询向量最相似的向量。这种搜索功能可以用于各种应用程序,例如图像搜索、相似产品推荐等。
39
-
40
- 一个具体的例子是,假设你有一个电商网站,你想为每个产品存储一个向量表示其特征。你可以使用Elasticsearch来存储这些向量,并使用KNN搜索来查找与用户查询最相似的产品。例如,当用户搜索“黑色运动鞋”,KNN搜索可以找到最接近这个查询向量的产品向量,并推荐给用户。这样可以提高用户体验,增加销售额。
41
-
42
- 怎么用knn给黑色运动鞋编码?对于KNN搜索,我们需要将向量嵌入到特征空间中,并计算向量之间的距离来找到最相似的向量。对于黑色运动鞋,我们可以使用各种特征来编码它,例如:
43
- - 鞋子的大小
44
- - 鞋子的材质
45
- - 鞋子的颜色
46
- - 鞋子的形状
47
- - 鞋子的品牌
48
- - 鞋子的价格
49
-
50
-
51
- 我们可以将这些特征组成一个向量,并使用一种嵌入技术(如Word2Vec)将其映射到一个向量空间中。这样,我们就可以使用KNN算法来搜索最相似的向量,即最相似的黑色运动鞋。
52
-
53
- 比如我们用以下特征来编码黑色运动鞋:
54
- - 鞋子的大小为10
55
- - 鞋子的材质为皮革
56
- - 鞋子的颜色为黑色
57
- - 鞋子的形状为运动鞋
58
- - 鞋子的品牌为Adidas
59
- - 鞋子的价格为100元
60
-
61
-
62
- 我们可以将这些特征组成一个长度为6的向量:
63
- - ` [10, 0, 0, 0, 1, 100] `
64
-
17
+ 向量搜索可利用机器学习来捕获非结构化数据(包括文本和图像)的含义和上下文,并将其转换为数字化表示形式。** 向量搜索常用于语义搜索** ,通过利用相似最近邻 (ANN) 算法来找到相似数据。与传统的关键字搜索相比,向量搜索产生的结果相关度更高。** 向量embedding除了捕获文本之外,还能捕获非结构化数据,如视频、图像和音频** 。它可以根据上下文快速为查询提供答案。这是因为** 向量embedding可捕获同义词和关联,它们本质上是搜索背后的含义** 。可以将向量搜索与筛选和聚合相结合,通过实现混合搜索并将其与传统评分相结合来优化相关性,从而增强搜索体验。
65
18
66
- 其中,第一个元素表示鞋子的大小,第二个元素表示鞋子的材质,第三个元素表示鞋子的颜色,第四个元素表示鞋子的形状,第五个元素表示鞋子的品牌,最后一个元素表示鞋子的价格。
19
+ ** 向量可以被用来比较,比如使用cosine比较向量的相似度** :
20
+ > These embeddings can then be compared e.g. with cosine-similarity to find sentences with a similar meaning.
67
21
22
+ 向量相似度可以用来查找和一个句子相似的语义,常用场景:
23
+ - [ 语义搜索] ( https://sbert.net/examples/applications/semantic-search/README.html )
24
+ - [ 语义挖掘] ( https://sbert.net/examples/applications/paraphrase-mining/README.html )
25
+ - [ 图片搜索] ( https://sbert.net/examples/applications/image-search/README.html )
68
26
69
- 然后,我们可以使用嵌入技术(如Word2Vec)将这个向量映射到一个向量空间中,例如:
70
- - ` [-0.12, 0.56, 0.23, -0.87, 0.43, 0.76] `
27
+ ## 向量编码
28
+ 将文本编码为向量,使用 [ sbert ] ( https://sbert.net/ ) 。相比于bert,sbert针对句子进行了优化。
71
29
72
- 现在,我们可以使用KNN算法来搜索与这个向量最相似的其他向量,就可以推荐给用户最相似的黑色运动鞋了。
30
+ > [ sbert ] ( https://sbert.net/ ) 的文档写得非常好!
73
31
74
- 我可以随机mock几个商品,并计算它们与黑色运动鞋之间的相似度。这里我先随机mock三个商品:
75
- - 商品1:尺码9,材料为纺织品,颜色为蓝色,形状为跑步鞋,品牌为Nike,价格为80元。
76
- - 商品2:尺码10,材料为皮革,颜色为白色,形状为篮球鞋,品牌为Jordan,价格为200元。
77
- - 商品3:尺码11,材料为纺织品,颜色为黑色,形状为足球鞋,品牌为Puma,价格为120元。
78
-
79
- 假设我们已经将这些商品的特征编码,并使用嵌入技术将它们映射到向量空间中。现在,我们可以使用KNN算法来计算它们与黑色运动鞋之间的相似度。
80
-
81
- 假设我们已经将黑色运动鞋和其他商品的特征编码成向量,并使用嵌入技术将它们映射到向量空间中。现在,我们可以使用余弦相似度来计算它们之间的相似度。余弦相似度的计算公式如下:
82
-
83
- ```
84
- similarity = cos(theta) = Dot Product(A, B) / (||A|| * ||B||)
85
- ```
86
-
87
- 其中,A和B分别是两个向量,||A||和||B||分别是它们的模长(即长度),Dot Product(A, B)是它们的点积,也就是对应元素相乘后再求和。
88
-
89
-
90
- 例如,在上面的例子中,假设黑色运动鞋的向量为:
91
- - ` [-0.12, 0.56, 0.23, -0.87, 0.43, 0.76] `
92
-
93
- 商品1的向量为:
94
- - ` [9, 1, 0, 1, 2, 80] `
95
-
96
-
97
- 我们可以将商品1的向量归一化为单位向量,即:
98
- - ` [0.11, 0.01, 0, 0.01, 0.02, 0.99] `
99
-
100
-
101
- 现在,我们可以计算它们的余弦相似度:` similarity = Dot Product([-0.12, 0.56, 0.23, -0.87, 0.43, 0.76], [0.11, 0.01, 0, 0.01, 0.02, 0.99]) / (||[-0.12, 0.56, 0.23, -0.87, 0.43, 0.76]|| * ||[0.11, 0.01, 0, 0.01, 0.02, 0.99]||) = 0.425 `
102
-
103
- 这样,我们就计算出了商品1和黑色运动鞋之间的相似度。按照同样的方法,可以计算出商品2和商品3与黑色运动鞋之间的相似度。
104
-
105
- # 向量编码
106
- 使用[ sbert] ( https://huggingface.co/sentence-transformers/paraphrase-multilingual-mpnet-base-v2 ) 的多语言版本,相比于bert,sbert针对句子进行了优化。
32
+ 它有多语言版本[ paraphrase-multilingual-mpnet-base-v2] ( (https://huggingface.co/sentence-transformers/paraphrase-multilingual-mpnet-base-v2) ) ,是对称语义搜索模型。
107
33
108
34
输出向量:
109
35
- 维度:768
@@ -123,6 +49,23 @@ sentence-transformers的模型默认优先使用GPU,无需额外设置。
123
49
124
50
milvus强制使用单位向量,elasticsearch可以不使用,但最好也使用单位向量。
125
51
52
+ ## 非/对称语义搜索
53
+ [ 语义搜索] ( https://sbert.net/examples/applications/semantic-search/README.html ) 又分为两种:
54
+ - symmetirc semantic search:对称语义搜索。query和目标语料体量相似,所以把语料和query交换位置(flip the query and the entries in your corpus),二者也是相似的。
55
+ - asymmetric semantic search:非对称语义搜索。分为question和answer,question体量一般较小,answer体量较大。如果颠倒过来,几乎就没有什么意义了(flipping the query and the entries in your corpus usually does not make sense);
56
+
57
+ ## knn
58
+ [ knn(k-nearest neighbor,k近邻)算法] ( https://www.elastic.co/what-is/knn/ ) ,用来求不同点之间的距离。有多种距离计算方法:
59
+ - Euclidean distance:欧几里得距离,x + y
60
+ - Manhattan distance:曼哈顿距离,也是我们常用的坐标系中的距离,是x^2 + y^2再开根号;
61
+ - 还有其他距离;
62
+
63
+ 余弦则可以用来计算两个向量的相似性,也就是人们常说的“小xx”,和上述距离相比,区别大概是:
64
+ - 距离是两个人绝对实力的差距,比如梅西和c罗实力接近,他们的曼哈顿距离接近;
65
+ - 相似性是两个人的技术特征相似,比如“小梅西”指一个人技术风格和梅西比较像,但是实力可能相去甚远;
66
+
67
+ ** 当我们需要衡量两个向量之间的相似度时,余弦相似度通常是一个很好的选择。而在需要考虑绝对差异的情况下,如KNN算法中,我们通常使用欧几里得距离来计算点之间的距离** 。
68
+
126
69
## demo
127
70
- 工程地址:[ bertsearch] ( https://github.com/puppylpg/bertsearch )
128
71
- [ 部署说明] ( https://github.com/puppylpg/bertsearch/blob/master/example/README.md )
@@ -143,8 +86,17 @@ milvus强制使用单位向量,elasticsearch可以不使用,但最好也使
143
86
144
87
milvus作为专用向量数据库,[ 支持的ANN算法比较多] ( https://milvus.io/docs/index.md ) ,使用不同的算法需要给字段设置不同的索引。
145
88
89
+ ## 向量量化
90
+ [ Embedding Quantization] ( https://sbert.net/examples/applications/embedding-quantization/README.html ) ,或者说[ Vector Quantization] ( https://en.wikipedia.org/wiki/Vector_quantization ) ,是指将连续的向量空间中的数据点映射到一个有限的离散集合中的过程。这种技术常用于数据压缩和数据编码中,** 通过将连续数据点用离散的符号表示,从而减少数据的存储空间或传输带宽要求** 。
91
+
92
+ ** 所以向量量化是以牺牲精度为代价,换取存储和查询性能的。**
93
+
146
94
# 向量数据库
147
- 目前行业top1是milvus,基于内存做搜索。elasticsearch7支持knn,8支持ann,基于磁盘做搜索。
95
+ 向量的搜索为必要借助数据库,在做一些demo的时候,可以直接提供source vector和destination vectors,直接使用一些库来完成向量的相似度检索。比如[ 使用hnswlib] ( https://github.com/UKPLab/sentence-transformers/blob/master/examples/applications/semantic-search/semantic_search_quora_hnswlib.py ) 。
96
+
97
+ 工程上一般选择向量数据库存储目标向量,目前行业top1是milvus,基于内存做搜索。elasticsearch7支持knn,8支持ann,基于磁盘做搜索。
98
+
99
+ 这里也有一个[ 使用elasticsearch做向量搜索的例子] ( https://github.com/UKPLab/sentence-transformers/blob/master/examples/applications/semantic-search/semantic_search_quora_elasticsearch.py ) 。
148
100
149
101
## elasticsearch8
150
102
版本选择
@@ -272,7 +224,7 @@ elasticsearch的7和8版本对向量搜索有不同程度的支持,使用起
272
224
273
225
> 这些参数参考[ 为spring-data-elasticsearch添加的` dense_vector ` mapping] ( https://github.com/spring-projects/spring-data-elasticsearch/pull/2920 ) 。
274
226
275
- ** [ 向量的量化(Vector Quantization) ] ( https://en.wikipedia.org/wiki/Vector_quantization ) ** ,是指将连续的向量空间中的数据点映射到一个有限的离散集合中的过程。这种技术常用于数据压缩和数据编码中, ** 通过将连续数据点用离散的符号表示,从而减少数据的存储空间或传输带宽要求 ** 。
227
+
276
228
277
229
## 向量搜索
278
230
不同的向量存储方式对应了不同的搜索方式,性能也相差较大。
@@ -589,5 +541,85 @@ es的向量可以来自于外部手动编码,也可以使用es提供的向量
589
541
## 其他注意事项
590
542
[ 调优] ( https://www.elastic.co/guide/en/elasticsearch/reference/8.13/tune-knn-search.html )
591
543
544
+ # 附:ChatGPT
545
+ 在最开始,向量相似度的相关问题我是通过ChatGPT来整理的。
546
+
547
+ 余弦相似度通常用于衡量两个向量之间的相似度,它在文本分类、推荐系统等领域有广泛应用。
548
+
549
+ 在文本分类中,我们通常使用向量空间模型(Vector Space Model)来表示文本,将每个文档表示为一个向量,其中每个维度表示一个词语。这些向量可以使用余弦相似度来计算它们之间的相似度,从而进行分类。
550
+
551
+ 在推荐系统中,我们通常使用协同过滤算法来推荐物品。协同过滤算法需要计算用户之间的相似度,以确定哪些用户具有相似的兴趣。在这种情况下,我们通常使用余弦相似度来计算用户之间的相似度,因为它可以很好地衡量它们之间的夹角,即它们之间的兴趣相似度。
552
+
553
+ 因此,** 当我们需要衡量两个向量之间的相似度时,余弦相似度通常是一个很好的选择。而在需要考虑绝对差异的情况下,如KNN算法中,我们通常使用欧几里得距离来计算点之间的距离** 。
554
+
555
+ ## 编码方式
556
+ Elasticsearch的KNN是指基于k最近邻算法的搜索功能。它允许用户在Elasticsearch中存储和搜索向量数据,并使用KNN算法来查找与查询向量最相似的向量。这种搜索功能可以用于各种应用程序,例如图像搜索、相似产品推荐等。
557
+
558
+ 一个具体的例子是,假设你有一个电商网站,你想为每个产品存储一个向量表示其特征。你可以使用Elasticsearch来存储这些向量,并使用KNN搜索来查找与用户查询最相似的产品。例如,当用户搜索“黑色运动鞋”,KNN搜索可以找到最接近这个查询向量的产品向量,并推荐给用户。这样可以提高用户体验,增加销售额。
559
+
560
+ 怎么用knn给黑色运动鞋编码?对于KNN搜索,我们需要将向量嵌入到特征空间中,并计算向量之间的距离来找到最相似的向量。对于黑色运动鞋,我们可以使用各种特征来编码它,例如:
561
+ - 鞋子的大小
562
+ - 鞋子的材质
563
+ - 鞋子的颜色
564
+ - 鞋子的形状
565
+ - 鞋子的品牌
566
+ - 鞋子的价格
567
+
568
+
569
+ 我们可以将这些特征组成一个向量,并使用一种嵌入技术(如Word2Vec)将其映射到一个向量空间中。这样,我们就可以使用KNN算法来搜索最相似的向量,即最相似的黑色运动鞋。
570
+
571
+ 比如我们用以下特征来编码黑色运动鞋:
572
+ - 鞋子的大小为10
573
+ - 鞋子的材质为皮革
574
+ - 鞋子的颜色为黑色
575
+ - 鞋子的形状为运动鞋
576
+ - 鞋子的品牌为Adidas
577
+ - 鞋子的价格为100元
578
+
579
+
580
+ 我们可以将这些特征组成一个长度为6的向量:
581
+ - ` [10, 0, 0, 0, 1, 100] `
582
+
583
+
584
+ 其中,第一个元素表示鞋子的大小,第二个元素表示鞋子的材质,第三个元素表示鞋子的颜色,第四个元素表示鞋子的形状,第五个元素表示鞋子的品牌,最后一个元素表示鞋子的价格。
585
+
586
+
587
+ 然后,我们可以使用嵌入技术(如Word2Vec)将这个向量映射到一个向量空间中,例如:
588
+ - ` [-0.12, 0.56, 0.23, -0.87, 0.43, 0.76] `
589
+
590
+ 现在,我们可以使用KNN算法来搜索与这个向量最相似的其他向量,就可以推荐给用户最相似的黑色运动鞋了。
591
+
592
+ 我可以随机mock几个商品,并计算它们与黑色运动鞋之间的相似度。这里我先随机mock三个商品:
593
+ - 商品1:尺码9,材料为纺织品,颜色为蓝色,形状为跑步鞋,品牌为Nike,价格为80元。
594
+ - 商品2:尺码10,材料为皮革,颜色为白色,形状为篮球鞋,品牌为Jordan,价格为200元。
595
+ - 商品3:尺码11,材料为纺织品,颜色为黑色,形状为足球鞋,品牌为Puma,价格为120元。
596
+
597
+ 假设我们已经将这些商品的特征编码,并使用嵌入技术将它们映射到向量空间中。现在,我们可以使用KNN算法来计算它们与黑色运动鞋之间的相似度。
598
+
599
+ 假设我们已经将黑色运动鞋和其他商品的特征编码成向量,并使用嵌入技术将它们映射到向量空间中。现在,我们可以使用余弦相似度来计算它们之间的相似度。余弦相似度的计算公式如下:
600
+
601
+ ```
602
+ similarity = cos(theta) = Dot Product(A, B) / (||A|| * ||B||)
603
+ ```
604
+
605
+ 其中,A和B分别是两个向量,||A||和||B||分别是它们的模长(即长度),Dot Product(A, B)是它们的点积,也就是对应元素相乘后再求和。
606
+
607
+
608
+ 例如,在上面的例子中,假设黑色运动鞋的向量为:
609
+ - ` [-0.12, 0.56, 0.23, -0.87, 0.43, 0.76] `
610
+
611
+ 商品1的向量为:
612
+ - ` [9, 1, 0, 1, 2, 80] `
613
+
614
+
615
+ 我们可以将商品1的向量归一化为单位向量,即:
616
+ - ` [0.11, 0.01, 0, 0.01, 0.02, 0.99] `
617
+
618
+
619
+ 现在,我们可以计算它们的余弦相似度:` similarity = Dot Product([-0.12, 0.56, 0.23, -0.87, 0.43, 0.76], [0.11, 0.01, 0, 0.01, 0.02, 0.99]) / (||[-0.12, 0.56, 0.23, -0.87, 0.43, 0.76]|| * ||[0.11, 0.01, 0, 0.01, 0.02, 0.99]||) = 0.425 `
620
+
621
+ 这样,我们就计算出了商品1和黑色运动鞋之间的相似度。按照同样的方法,可以计算出商品2和商品3与黑色运动鞋之间的相似度。
622
+
592
623
# 感想
593
624
大人,时代变了。从es的发展就可以看出,纯分词搜索依然必要,但终归也是要拥抱算法的。
625
+
0 commit comments