密集向量数组和余弦相似度
Dense vector array and cosine similarity
我想在我的文档中存储一个 dense_vector
的数组,但这并不适用于其他数据类型,例如
PUT my_index
{
"mappings": {
"properties": {
"my_vectors": {
"type": "dense_vector",
"dims": 3
},
"my_text" : {
"type" : "keyword"
}
}
}
}
PUT my_index/_doc/1
{
"my_text" : "text1",
"my_vector" : [[0.5, 10, 6], [-0.5, 10, 10]]
}
returns:
'1 document(s) failed to index.',
{'_index': 'my_index', '_type': '_doc', '_id': 'some_id', 'status': 400, 'error':
{'type': 'mapper_parsing_exception', 'reason': 'failed to parse', 'caused_by':
{'type': 'parsing_exception',
'reason': 'Failed to parse object: expecting token of type [VALUE_NUMBER] but found [START_ARRAY]'
}
}
}
如何实现?不同的文档将具有可变数量的矢量,但绝不会超过少数。
此外,我想通过对该数组中的每个值执行 cosineSimilarity
来查询它。下面的代码是当我在文档中只有一个向量时我通常是这样做的。
"script_score": {
"query": {
"match_all": {}
},
"script": {
"source": "(1.0+cosineSimilarity(params.query_vector, doc['my_vectors']))",
"params": {"query_vector": query_vector}
}
}
理想情况下,我想要最接近的相似度或平均值。
dense_vector
数据类型旨在
stores dense vectors of float values (from documentation) .... A dense_vector field is a single-valued field.
在您的示例中,您希望在同一个 属性 中索引多个向量。但正如文档中所述,您的字段必须是单值的。如果您的文档有多个向量,则需要将它们分派到不同的属性中。
没有解决方法:(
因此您需要在不同的字段中分派向量,然后在脚本中使用循环并保留最合适的值。
dense_vector
数据类型要求每个文档有一个数值数组,如下所示:
PUT my_index/_doc/1
{
"my_text" : "text1",
"my_vector" : [0.5, 10, 6]
}
要存储任意数量的向量,您可以将 my_vector
字段设为“嵌套”类型,其中包含一个对象数组,每个对象包含一个向量:
PUT my_index
{
"mappings": {
"properties": {
"my_vectors": {
"type": "nested",
"properties": {
"vector": {
"type": "dense_vector",
"dims": 3
}
}
},
"my_text" : {
"type" : "keyword"
}
}
}
}
PUT my_index/_doc/1
{
"my_text" : "text1",
"my_vector" : [
{"vector": [0.5, 10, 6]},
{"vector": [-0.5, 10, 10]}
]
}
编辑
然后,要查询文档,您可以使用以下方法(自 ES v7.6.1 起)
{
"query": {
"nested": {
"path": "my_vectors",
"score_mode": "max",
"query": {
"function_score": {
"script_score": {
"script": {
"source": "(1.0+cosineSimilarity(params.query_vector, 'my_vectors.vector'))",
"params": {"query_vector": query_vector}
}
}
}
}
}
}
}
注意事项:
- 查询需要包含在
nested
声明中(由于使用嵌套对象来存储向量)
- 因为嵌套对象是单独的 Lucene 文档,嵌套对象是单独评分的,默认情况下,父文档被分配匹配嵌套文档的平均分数。您可以指定嵌套的 属性
score_mode
来更改评分行为。对于您的情况,“最大”将根据描述最相似文档的最大余弦相似度得分进行评分。
- 如果您有兴趣查看每个嵌套向量的分数,可以使用嵌套 属性
inner_hits
.
- 如果有人好奇为什么将 +1.0 添加到余弦相似度分数,那是因为 Cos.Sim。计算值 [-1,1],但 ElasticSearch 不能有负分。因此,分数被转换为 [0,2].
我想在我的文档中存储一个 dense_vector
的数组,但这并不适用于其他数据类型,例如
PUT my_index
{
"mappings": {
"properties": {
"my_vectors": {
"type": "dense_vector",
"dims": 3
},
"my_text" : {
"type" : "keyword"
}
}
}
}
PUT my_index/_doc/1
{
"my_text" : "text1",
"my_vector" : [[0.5, 10, 6], [-0.5, 10, 10]]
}
returns:
'1 document(s) failed to index.',
{'_index': 'my_index', '_type': '_doc', '_id': 'some_id', 'status': 400, 'error':
{'type': 'mapper_parsing_exception', 'reason': 'failed to parse', 'caused_by':
{'type': 'parsing_exception',
'reason': 'Failed to parse object: expecting token of type [VALUE_NUMBER] but found [START_ARRAY]'
}
}
}
如何实现?不同的文档将具有可变数量的矢量,但绝不会超过少数。
此外,我想通过对该数组中的每个值执行 cosineSimilarity
来查询它。下面的代码是当我在文档中只有一个向量时我通常是这样做的。
"script_score": {
"query": {
"match_all": {}
},
"script": {
"source": "(1.0+cosineSimilarity(params.query_vector, doc['my_vectors']))",
"params": {"query_vector": query_vector}
}
}
理想情况下,我想要最接近的相似度或平均值。
dense_vector
数据类型旨在
stores dense vectors of float values (from documentation) .... A dense_vector field is a single-valued field.
在您的示例中,您希望在同一个 属性 中索引多个向量。但正如文档中所述,您的字段必须是单值的。如果您的文档有多个向量,则需要将它们分派到不同的属性中。
没有解决方法:(
因此您需要在不同的字段中分派向量,然后在脚本中使用循环并保留最合适的值。
dense_vector
数据类型要求每个文档有一个数值数组,如下所示:
PUT my_index/_doc/1
{
"my_text" : "text1",
"my_vector" : [0.5, 10, 6]
}
要存储任意数量的向量,您可以将 my_vector
字段设为“嵌套”类型,其中包含一个对象数组,每个对象包含一个向量:
PUT my_index
{
"mappings": {
"properties": {
"my_vectors": {
"type": "nested",
"properties": {
"vector": {
"type": "dense_vector",
"dims": 3
}
}
},
"my_text" : {
"type" : "keyword"
}
}
}
}
PUT my_index/_doc/1
{
"my_text" : "text1",
"my_vector" : [
{"vector": [0.5, 10, 6]},
{"vector": [-0.5, 10, 10]}
]
}
编辑
然后,要查询文档,您可以使用以下方法(自 ES v7.6.1 起)
{
"query": {
"nested": {
"path": "my_vectors",
"score_mode": "max",
"query": {
"function_score": {
"script_score": {
"script": {
"source": "(1.0+cosineSimilarity(params.query_vector, 'my_vectors.vector'))",
"params": {"query_vector": query_vector}
}
}
}
}
}
}
}
注意事项:
- 查询需要包含在
nested
声明中(由于使用嵌套对象来存储向量) - 因为嵌套对象是单独的 Lucene 文档,嵌套对象是单独评分的,默认情况下,父文档被分配匹配嵌套文档的平均分数。您可以指定嵌套的 属性
score_mode
来更改评分行为。对于您的情况,“最大”将根据描述最相似文档的最大余弦相似度得分进行评分。 - 如果您有兴趣查看每个嵌套向量的分数,可以使用嵌套 属性
inner_hits
. - 如果有人好奇为什么将 +1.0 添加到余弦相似度分数,那是因为 Cos.Sim。计算值 [-1,1],但 ElasticSearch 不能有负分。因此,分数被转换为 [0,2].