云服务器内容精选

  • 导入向量数据 执行如下命令,导入向量数据。向“my_index”索引中写入向量数据时,需要指定向量字段名称和向量数据。 向量数据输入格式为逗号分隔的浮点型数组时: POST my_index/_doc { "my_vector": [1.0, 2.0] } 向量数据输入格式为小端字节序编码的Base64字符串时: 在写入二值向量,或向量维度较高、数值有效位较多时,使用Base64编码格式传输、解析更加高效。 POST my_index/_doc { "my_vector": "AACAPwAAAEA=" } 当写入大规模数据时,建议使用Bulk操作: POST my_index/_bulk {"index": {}} {"my_vector": [1.0, 2.0], "my_label": "red"} {"index": {}} {"my_vector": [2.0, 2.0], "my_label": "green"} {"index": {}} {"my_vector": [2.0, 3.0], "my_label": "red"}
  • 创建向量索引 登录 云搜索服务 管理控制台。 在“集群管理”页面,选择需要启用向量检索的集群,单击操作列“Kibana”,登录Kibana界面。 单击左侧导航栏的“Dev Tools”,执行如下命令创建向量索引。 创建一个名为“my_index”的索引,该索引包含一个名为“my_vector”的向量字段和一个名为“my_label”的文本字段。其中,向量字段创建了GRAPH图索引,并使用欧式距离作为相似度度量。 PUT my_index { "settings": { "index": { "vector": true } }, "mappings": { "properties": { "my_vector": { "type": "vector", "dimension": 2, "indexing": true, "algorithm": "GRAPH", "metric": "euclidean" }, "my_label": { "type": "keyword" } } } } 表3 创建索引参数说明 类型 参数 说明 Index settings参数 vector 当需要使用向量索引加速时,需要设置该值为true。 Field mappings参数 type 字段类型,“vector”表示该字段为向量字段。 dimension 向量数据维度。取值范围:[1, 4096]。 indexing 是否开启向量索引加速。 可选值: false:表示关闭向量索引加速,向量数据仅写入docvalues,只支持使用ScriptScore以及Rescore进行向量查询。 true:表示开启向量索引加速,系统将创建额外的向量索引,索引算法由"algorithm"字段指定,写入数据后可以使用VectorQuery进行查询。 默认值:false。 algorithm 索引算法。仅当“indexing”为“true”时生效。 可选值: FLAT:暴力计算,目标向量依次和所有向量进行距离计算,此方法计算量大,召回率100%。适用于对召回准确率要求极高的场景。 GRAPH:图索引,内嵌深度优化的HNSW算法,主要应用在对性能和精度均有较高要求且单shard中文档数量在千万个以内的场景。 GRAPH_PQ:将HNSW算法与PQ算法进行了结合,通过PQ降低原始向量的存储开销,能够使HNSW轻松支撑上亿规模的检索场景。 IVF_GRAPH:算法将IVF与HNSW结合,对全量空间进行划分,每一个聚类中心向量代表了一个子空间,极大地提升检索效率,同时会带来微小的检索精度损失。适用于数据量在上亿以上同时对检索性能要求较高的场景。 IVF_GRAPH_PQ:PQ算法与IVF-HNSW的结合,PQ可以通过配置选择与HNSW结合和IVF结合,进一步提升系统的容量并降低系统开销,适用于shard中文档数量在十亿级别以上同时对检索性能要求较高的场景。 默认值:GRAPH。 说明: 当选择IVF_GRAPH或者IVF_GRAPH_PQ索引时,需要额外进行预构建中心点索引以及注册等步骤,具体内容请参考(可选)预构建与注册中心点向量。 其他可选参数 当使用向量索引加速时(即“indexing”为“true”时),为了获得更高的查询性能以及查询精度, CSS 提供了与向量索引相关的可选参数配置,参数说明请参见表4。 metric 计算向量之间距离的度量方式。 可选值: euclidean:欧式距离。 inner_product:内积距离。 cosine:余弦距离。 hamming:汉明距离,仅支持设置"dim_type"为"binary"时使用。 默认值:euclidean。 dim_type 向量维度值的类型。 可选值:binary、float(默认)。 表4 可选参数说明 类型 参数 说明 GRAPH类索引配置参数 neighbors 图索引中每个向量的邻居数,默认值为64,值越大查询精度越高。索引越大,构建速度以及后续的查询速度也会变慢。 取值范围:[10, 255]。 shrink 构建hnsw时的裁边系数,默认值1.0f。 取值范围:(0.1, 10)。 scaling 构建hnsw时上层图节点数的缩放比例,默认值50。 取值范围:(0, 128]。 efc 构建hnsw时考察邻居节点的队列大小,默认值为200,值越大精度越高,构建速度将会变慢。 取值范围:(0, 100000]。 max_scan_num 扫描节点上限,默认值为10000,值越大精度越高,索引速度变慢。 取值范围:(0, 1000000]。 PQ类索引配置参数 centroid_num 每一段的聚类中心点数目,默认值为255。 取值范围:(0, 65535]。 fragment_num 段数,默认值为0,插件自动根据向量长度设置合适的段数。 取值范围:[0, 4096]。
  • (可选)预构建与注册中心点向量 当创建向量索引时选择使用“IVF_GRAPH”和“IVF_GRAPH_PQ”的索引算法,则需要对中心点向量进行预构建和注册。 在向量索引加速算法中,“IVF_GRAPH”和“IVF_GRAPH_PQ”适用于超大规模场景。这两种算法需要通过对子空间的切割缩小查询范围,子空间的划分通常采用聚类或者随机采样的方式。在预构建之前,需要通过聚类或者随机采样得到所有的中心点向量。通过预构建和注册将中心点向量预构建成GRAPH或者GRAPH_PQ索引,同时注册到 CS S集群内,实现在多个节点间共享此索引文件。中心点索引在shard间复用能够有效减少训练的开销、中心点索引的查询次数,提升写入以及查询的性能。 选择启用向量检索的集群,单击操作列“Kibana”,登录Kibana界面。 单击左侧导航栏的“Dev Tools”,进入操作界面。 创建中心点索引表。 创建的索引命名为my_dict,注意该索引的number_of_shards数必须设置为1,否则无法注册。 当需要使用IVF_GRAPH索引时,中心点索引的algorithm设置为GRAPH。 当需要使用IVF_GRAPH_PQ索引时,中心点索引的algorithm设置为GRAPH_PQ。 PUT my_dict { "settings": { "index": { "vector": true }, "number_of_shards": 1, "number_of_replicas": 0 }, "mappings": { "properties": { "my_vector": { "type": "vector", "dimension": 2, "indexing": true, "algorithm": "GRAPH", "metric": "euclidean" } } } } 写入中心点向量数据。 参考导入向量数据将采样或者聚类得到的中心点向量写入上述创建的my_dict索引中。 调用注册接口。 将上述创建的my_dict索引注册具有全局唯一标识名称(dict_name)的Dict对象。 PUT _vector/register/my_dict { "dict_name": "my_dict" } 创建IVF_GRAPH或IVF_GRAPH_PQ索引。 在创建IVF_GRAPH或者IVF_GRAPH_PQ索引时,不再需要指定dimension以及metric信息,只需指定之前注册好的dict名称即可。 PUT my_index { "settings": { "index": { "vector": true, "sort.field": "my_vector.centroid" # 将向量字段的centroid子字段设置为排序字段 } }, "mappings": { "properties": { "my_vector": { "type": "vector", "indexing": true, "algorithm": "IVF_GRAPH", "dict_name": "my_dict", "offload_ivf": true } } } } 表2 Field mappings参数 参数 说明 dict_name 指定依赖的中心点索引名称。该索引字段的向量维度和度量方式将与dict索引保持一致,不再需要额外指定。 offload_ivf 将底层索引实现的IVF倒排索引卸载到ES端实现,可以减少堆外内存的使用,以及减少写入/合并的性能开销。建议设置为true。 取值范围:true、false。 默认值:false。
  • (可选)准备工作 在创建向量索引前,请根据业务场景,完成集群高级配置。 在离线导入数据场景下,为了提高批量写入性能,建议将索引的“refresh_interval”参数设置为“-1”,即关闭自动刷新索引。 建议将备份数“number_of_replicas”设置为“0”,当离线数据导入完成后,再设置为需要的值。 其他高级功能的参数配置说明请参见表1。 表1 集群高级配置参数说明 参数 说明 native.cache.circuit_breaker.enabled 是否开启堆外内存熔断。 默认值:true。 native.cache.circuit_breaker.cpu.limit 向量索引堆外内存使用上限。 假设使用128GB内存的机器且堆内存大小为31GB,默认堆外内存使用上限为(128 - 31) * 45% = 43.65GB,堆外内存使用量超过该值将会触发写入熔断。 默认值:45%。 native.cache.expire.enabled 是否开启缓存超时设置。开启时,如果某些缓存项长时间没有被访问过将会被清除。 取值范围:true、false。 默认值:false。 native.cache.expire.time 超时时长。 默认值:24h。 native.vector.index_threads 创建底层索引时所使用的线程数,每个shard均会使用多个构建线程。该值建议不要设置过大,避免产生过多的构建线程抢占查询资源。 默认值:4。
  • 标准查询 针对创建了向量索引的向量字段,提供了标准向量查询语法。下述查询命令将会返回所有数据中与查询向量最近的size(topk)条数据。 POST my_index/_search { "size":2, "_source": false, "query": { "vector": { "my_vector": { "vector": [1, 1], "topk":2 } } } } 表1 标准查询的参数说明 参数 说明 vector(第一个) 表示该查询类型为VectorQuery。 my_vector 指定了需要查询的向量字段名称。 vector(第二个) 指定查询向量的具体值,支持数组形式以及Base64编码形式的输入。 topk topk的值通常与size保持一致。 其他可选的查询参数 通过调整不同索引的查询参数,可以获得更高的查询性能或者查询精度,其他参数请参见表2。 表2 可选的查询参数说明 参数 子参数 说明 GRAPH类索引配置参数 ef 查询时考察邻居节点的队列大小。值越大查询精度越高,查询速度会变慢。默认值为200。 取值范围:(0, 100000]。 max_scan_num 扫描节点上限。值越大精度越高,查询速度变慢。默认值为10000。 取值范围:(0, 1000000]。 IVF类索引配置参数 nprobe 查询考察中心点的数目。值越大精度越高,查询速度变慢。默认值为100。 取值范围:(0, 100000]。
  • 复合查询 向量检索支持与其他ES子查询组合进行复合查询,比如布尔查询、后置过滤等。 以下两个示例的查询结果:首先查询top10条与查询向量距离最近的结果,filter作为过滤条件将仅保留my_label字段为“red”的结果。 布尔查询示例 POST my_index/_search { "size": 10, "query": { "bool": { "must": { "vector": { "my_vector": { "vector": [1, 2], "topk": 10 } } }, "filter": { "term": { "my_label": "red" } } } } } 后置过滤示例 GET my_index/_search { "size": 10, "query": { "vector": { "my_vector": { "vector": [1, 2], "topk": 10 } } }, "post_filter": { "term": { "my_label": "red" } } }
  • 重打分查询 当使用GRAPH_PQ索引或者IVF_GRAPH_PQ索引时,查询结果是根据PQ计算的非对称距离进行排序。CSS支持Rescore的方式对查询结果进行重打分精排,提升召回率。 假设my_index是PQ类型的索引,Rescore示例如下: GET my_index/_search { "size": 10, "query": { "vector": { "my_vector": { "vector": [1.0, 2.0], "topk": 100 } } }, "rescore": { "window_size": 100, "vector_rescore": { "field": "my_vector", "vector": [1.0, 2.0], "metric": "euclidean" } } } 表4 Rescore参数说明 参数 说明 window_size 向量检索将会返回topk条结果,仅取前window_size条结果精排。 field 向量字段名称。 vector 查询向量数据。 metric 度量方式,可选值为:euclidean、inner_product、cosine、hamming。 默认值:euclidean。
  • Painless语法扩展查询 CSS扩展实现了多种向量距离计算函数,可在自定义的painless脚本中直接使用,用以构建灵活的重打分公式。 示例如下: POST my_index/_search { "size": 10, "query": { "script_score": { "query": { "match_all": {} }, "script": { "source": "1 / (1 + euclidean(params.vector, doc[params.field]))", "params": { "field": "my_vector", "vector": [1, 2] } } } } } 表5 支持的距离计算函数 函数签名 说明 euclidean(Float[], DocValues) 欧式距离函数。 cosine(Float[], DocValues) 余弦相似度函数。 innerproduct(Float[], DocValues) 内积函数。 hamming(String, DocValues) 汉明距离函数。只支持"dim_type"为"binary"的向量字段,输入的查询向量需要为Base64编码字符串格式。
  • ScriptScore查询 写入向量数据后,针对向量字段可以使用ScriptScore进行最近邻查询,查询语法如下所示。 前置过滤条件可以为任意查询,script_score仅针对前置过滤的结果进行遍历,计算向量相似度并排序返回。此种查询方式的性能取决于前置过滤后中间结果集的大小,当前置过滤条件为"match_all"时,相当于全局暴力检索。 POST my_index/_search { "size":2, "query": { "script_score": { "query": { "match_all": {} }, "script": { "source": "vector_score", "lang": "vector", "params": { "field": "my_vector", "vector": [1.0, 2.0], "metric": "euclidean" } } } } } 表3 script_score参数说明 参数 说明 source script脚本描述,使用向量相似度打分时为固定值"vector_score"。 lang script语法描述,使用固定值"vector"。 field 向量字段名称。 vector 查询向量数据。 metric 度量方式,可选值为:euclidean、inner_product、cosine、hamming。 默认值:euclidean。
  • 代码示例 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 from opensearchpy import OpenSearch # 创建客户端 def get_client(hosts: list, user: str = None, password: str = None): if user and password: return OpenSearch(hosts, http_auth=(user, password), verify_certs=False, ssl_show_warn=False) else: return OpenSearch(hosts) # 创建索引表 def create(client: OpenSearch, index: str): # 索引mapping信息 index_mapping = { "settings": { "index": { "vector": "true", # 开启向量特性 "number_of_shards": 1, # 索引分片数,根据实际需求设置 "number_of_replicas": 0, # 索引副本数,根据实际需求设置 } }, "mappings": { "properties": { "my_vector": { "type": "vector", "dimension": 2, "indexing": True, "algorithm": "GRAPH", "metric": "euclidean" } # 可根据需求添加其他字段 } } } res = client.indices.create(index=index, body=index_mapping) print("create index result: ", res) # 写入数据 def write(client: OpenSearch, index: str, vecs: list, bulk_size=500): for i in range(0, len(vecs), bulk_size): actions = "" for vec in vecs[i: i + bulk_size]: actions += '{"index": {"_index": "%s"}}\n' % index actions += '{"my_vector": %s}\n' % str(vec) client.bulk(body=actions, request_timeout=3600) client.indices.refresh(index=index, request_timeout=3600) print("write index success!") # 查询向量索引 def search(client: OpenSearch, index: str, query: list[float], size: int): # 查询语句,可根据需求选择合适的查询方式 query_body = { "size": size, "query": { "vector": { "my_vector": { "vector": query, "topk": size } } } } res = client.search(index=index, body=query_body) print("search index result: ", res) # 删除索引 def delete(client: OpenSearch, index: str): res = client.indices.delete(index=index) print("delete index result: ", res) if __name__ == '__main__': os_client = get_client(hosts=['http://x.x.x.x:9200']) # 对于开启了https的安全集群,使用: # os_client = get_client(hosts=['https://x.x.x.x:9200', 'https://x.x.x.x:9200'], user='xxxxx', password='xxxxx') # 对于未开启https的安全集群,使用: # os_client = get_client(hosts=['http://x.x.x.x:9200', 'http://x.x.x.x:9200'], user='xxxxx', password='xxxxx') # 测试索引名称 index_name = "my_index" # 创建索引 create(os_client, index=index_name) # 写入数据 data = [[1.0, 1.0], [2.0, 2.0], [3.0, 3.0]] write(os_client, index=index_name, vecs=data) # 查询索引 query_vector = [1.0, 1.0] search(os_client, index=index_name, query=query_vector, size=3) # 删除索引 delete(os_client, index=index_name)