云服务器内容精选

  • 导入向量数据 执行如下命令,导入向量数据。向“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"}
  • (可选)离线构建 离线构建API仅适用于业务无实时性要求的场景,要求集群版本大于或等于Elasticsearch 7.10.2,且集群镜像版本号不低于7.10.2_24.3.3_x.x.x。 Elasticsearch使用类LSM-Tree写入模型,数据持续写入和更新的过程中会生成大量小的索引段,并通过后台合并任务不断合并成大的索引段,以提供更优的查询性能。由于向量索引的构建是计算密集型的,向量数据写入过程频繁的合并任务会消耗更多的CPU资源。因此,在数据实时性要求不高的场景,建议设置向量字段的“lazy_indexing”参数为“true”开启索引延迟构建,当全量数据写入完成后,再调用离线构建API完成向量索引的最终构建。使用离线构建功能可以有效减少合并过程中向量索引的重复构建,能够端到端提升写入和索引合并的性能。 离线构建的执行流程包含两个步骤: 合并索引段。 基于最终的索引段构建向量索引。 离线构建API的接口格式如下: POST _vector/indexing/{index_name} { "field": "{field_name}" } 其中,{index_name}为需要构建索引的索引名称,{field_name}为向量字段名称且该字段必须已经配置了“lazy_indexing”为“true”。 当开启了lazy_indexing延迟构建索引的向量字段,在写入数据后未调用离线构建API,则索引无法正常执行VectorQuery标准查询,该查询请求将会返回错误码500,错误信息中包含“Load native index failed exception”。此时,建议先执行离线构建再查询。
  • (可选)准备工作 在创建向量索引前,请根据业务场景,完成集群高级配置。 在离线导入数据场景下,为了提高批量写入性能,建议将索引的“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) * 80% = 77.6GB,堆外内存使用量超过该值将会触发写入熔断。 默认值:80%。 native.cache.expiry.enabled 是否开启缓存超时设置。开启时,如果某些缓存项长时间没有被访问过将会被清除。 取值范围:true、false。 默认值:false。 native.cache.expiry.time 超时时长。 默认值:24h。 native.vector.index_threads 创建底层索引时所使用的线程数,每个shard均会使用多个构建线程。该值建议不要设置过大,避免产生过多的构建线程抢占查询资源。 默认值:4。
  • 创建向量索引 登录 云搜索服务 管理控制台。 在“集群管理”页面,选择需要启用向量检索的集群,单击操作列“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。 vector.exact_search_threshold 用于设置在搜索过程中,从前置过滤搜索切换到暴力搜索的中间结果集大小的阈值控制参数。 当Segment中过滤后的中间结果集的数量小于该参数值时,则执行暴力搜索。 默认值为“null”,即不会切换为暴力搜索。 vector.search.concurrency.enabled 是否开启segment间并发搜索。在Elasticsearch中,每个索引分片由多个segment组成,执行查询时默认采用segment间串行搜索机制。启用并发搜索可通过并行执行搜索任务优化查询性能,这将有效降低查询时延,但不会提升集群的最大查询吞吐量。 开启该参数可能会提高集群的平均CPU使用率。 该参数仅在Elasticsearch 7.10.2集群且镜像版本号不低于7.10.2_25.3.0_x.x.x时才支持配置。 可选值: false:表示执行查询时采用segment间串行搜索机制。 true:表示执行查询时采用segment间并发搜索机制。 默认值:false Field mappings参数 type 字段类型,“vector”表示该字段为向量字段。 dimension 向量数据维度。取值范围:[1, 4096]。 indexing 是否开启向量索引加速。 可选值: false:表示关闭向量索引加速,向量数据仅写入docvalues,只支持使用ScriptScore以及Rescore进行向量查询。 true:表示开启向量索引加速,系统将创建额外的向量索引,索引算法由"algorithm"字段指定,写入数据后可以使用VectorQuery进行查询。 默认值:false。 lazy_indexing 是否开启向量索引延迟构建,仅用于离线构建场景。 仅在“indexing”为“true”,且集群版本为Elasticsearch 7.10.2、集群镜像版本号不低于7.10.2_24.3.3_x.x.x的情况下,配置lazy_indexing才会生效。 可选值: false:不开启。 true:开启延迟构建,此时写入向量数据时,集群不实时创建向量索引结构(比如图索引),而是在数据写入后执行离线构建,再开始创建向量索引结构。构建完成后才可使用VectorQuery进行查询。 algorithm 索引算法。仅当“indexing”为“true”时生效。 可选值: FLAT:暴力计算,目标向量依次和所有向量进行距离计算,此方法计算量大,召回率100%。适用于对召回准确率要求极高的场景。 GRAPH:图索引,内嵌深度优化的HNSW算法,主要应用在对性能和精度均有较高要求且单shard中文档数量在千万个以内的场景。 GRAPH_PQ:将HNSW算法与PQ算法进行了结合,通过PQ降低原始向量的存储开销,能够使HNSW轻松支撑上亿规模的检索场景。 GRAPH_SQ8:将HNSW算法与SQ量化算法进行了结合,将float32数值类型量化为int8,降低原始向量的存储开销,并提升构建和查询效率,但会带来一定的召回率下降。仅Elasticsearch 7.10.2版本的集群支持。 GRAPH_SQ4:将HNSW算法与SQ量化算法进行了结合,将float32数值类型量化为int4,降低原始向量的存储开销,并提升构建和查询效率,但会带来一定的召回率损失。SQ4量化压缩率高于SQ8,且计算效率更高,但召回率下降也会更多。仅Elasticsearch 7.10.2版本的集群支持。 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。
  • 代码示例 from elasticsearch import Elasticsearchfrom elasticsearch import helpers# 创建Elasticsearch客户端def get_client(hosts: list, user: str = None, password: str = None): if user and password: return Elasticsearch(hosts, http_auth=(user, password), verify_certs=False, ssl_show_warn=False) else: return Elasticsearch(hosts)# 创建索引表def create(client: Elasticsearch, 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: Elasticsearch, index: str, vecs: list, bulk_size=500): for i in range(0, len(vecs), bulk_size): actions = [ { "_index": index, "my_vector": vec, # 可根据需求添加其他字段 } for vec in vecs[i: i+bulk_size] ] success, errors = helpers.bulk(client, actions, request_timeout=3600) if errors: print("write bulk failed with errors: ", errors) # 根据需求进行错误处理 else: print("write bulk {} docs success".format(success)) client.indices.refresh(index=index, request_timeout=3600)# 查询向量索引def search(client: Elasticsearch, index: str, query: list, 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: Elasticsearch, index: str): res = client.indices.delete(index=index) print("delete index result: ", res)if __name__ == '__main__': # 对于非安全集群,使用: es_client = get_client(hosts=['http://x.x.x.x:9200']) # 对于开启了https的安全集群,使用: # es_client = get_client(hosts=['https://x.x.x.x:9200', 'https://x.x.x.x:9200'], user='xxxxx', password='xxxxx') # 对于未开启https的安全集群,使用: # es_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(es_client, index=index_name) # 写入数据 data = [[1.0, 1.0], [2.0, 2.0], [3.0, 3.0]] write(es_client, index=index_name, vecs=data) # 查询索引 query_vector = [1.0, 1.0] search(es_client, index=index_name, query=query_vector, size=3) # 删除索引 delete(es_client, index=index_name)