文档

使用云服务将Tablestore数据转成向量

更新时间:

本文以文本数据转换成向量为例介绍如何将存储在Tablestore中的文本数据通过阿里云模型服务灵积(DashScope)生成向量。

方案概览

阿里云模型服务灵积(DashScope)提供多种非结构化/结构化数据转换成向量数据的模型服务,可以将文本、语音、图片等转换成向量。更多信息,请参见模型服务灵积简介

使用DashScope将存储在Tablestore中的文本数据生成向量只需3步:

  1. 开通服务并获取API-KEY:DashScope通过API-KEY进行调用鉴权和计量计费。使用DashScope前,您需要开通模型服务灵积DashScope并获取API-KEY。

  2. 生成向量并写入到表格存储:使用DashScope生成向量后,将向量数据写入到表格存储数据表中存储。

  3. 结果验证:使用表格存储的数据读取接口或者多元索引向量检索功能查询数据。

image

使用说明

  • 开发语言:Java

  • Java版本:Java8及以上版本。

注意事项

Tablestore多元索引中向量类型的维度、类型、距离算法必须与DashScope中文本转向量模型的相应配置保持一致。例如DashScope中的text-embedding-async-v2模型生成的向量类型为1536维、Float32类型和dot_product点积距离算法,在Tablestore创建多元索引时的向量类型也必须是1536维、Float32类型和dot_product点积距离算法。

前提条件

  • 使用阿里云账号或者具有表格存储和模型服务灵积操作权限的RAM用户进行操作。

    如果要使用RAM用户进行操作,您需要使用阿里云账号创建RAM用户并授予RAM用户访问表格存储(AliyunOTSFullAccess)和服务模型灵积(AliyunDashscopeFullAccess)的权限。具体操作,请参见为RAM用户授权

  • 已为阿里云账号或者RAM用户创建AccessKey。具体操作,请参见创建AccessKey

  • 已获取表格存储实例的名称和服务地址。具体操作,请参见服务地址

  • 已将AccessKey(包括AccessKey ID和AccessKey Secret)、实例名称和实例的服务地址配置到环境变量中。

1. 开通服务并获取API-KEY

DashScope通过API-KEY进行调用鉴权和计量计费。使用DashScope前,您需要开通DashScope服务并获取API-KEY。

1.1 开通模型服务灵积DashScope

打开DashScope模型服务灵积控制台,在总览页面单击未开通,根据界面提示完成服务开通。

image

1.2 获取调用API所需凭证

在DashScope控制台的API-KEY管理页面,单击创建新的API-KEY来创建API-KEY用于调用API。

image

2. 生成向量并写入到表格存储

使用模型服务进行向量生成后,将向量写入到表格存储数据表中。具体步骤如下:

说明

此处以DashScope的Java SDK为例介绍向量的生成,其它语言SDK和模型请参见DashScope的文本向量多模态向量文档。

  1. 安装DashScope Java SDK和表格存储Java SDK。

    在Maven工程中使用DashScope Java SDK和表格存储Java SDK,只需在pom.xml中加入相应依赖即可。在<dependencies>内加入如下内容:

    <!--安装模型服务灵积Java SDK-->
    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>dashscope-sdk-java</artifactId>
        <version>最新版本</version>
    </dependency>
    <!--安装表格存储Java SDK-->
    <dependency>
        <groupId>com.aliyun.openservices</groupId>
        <artifactId>tablestore</artifactId>
        <version>最新版本</version>
    </dependency>   
  2. 生成向量并将向量写入表格存储中。

    以下示例使用DashScope生成维度为1536的向量,然后写入到表格存储中。

    import com.alibaba.dashscope.embeddings.TextEmbedding;
    import com.alibaba.dashscope.embeddings.TextEmbeddingParam;
    import com.alibaba.dashscope.embeddings.TextEmbeddingResult;
    import com.alicloud.openservices.tablestore.SyncClient;
    import com.alicloud.openservices.tablestore.model.BatchWriteRowRequest;
    import com.alicloud.openservices.tablestore.model.BatchWriteRowResponse;
    import com.alicloud.openservices.tablestore.model.ColumnValue;
    import com.alicloud.openservices.tablestore.model.CreateTableRequest;
    import com.alicloud.openservices.tablestore.model.Direction;
    import com.alicloud.openservices.tablestore.model.GetRangeRequest;
    import com.alicloud.openservices.tablestore.model.GetRangeResponse;
    import com.alicloud.openservices.tablestore.model.PrimaryKey;
    import com.alicloud.openservices.tablestore.model.PrimaryKeyBuilder;
    import com.alicloud.openservices.tablestore.model.PrimaryKeySchema;
    import com.alicloud.openservices.tablestore.model.PrimaryKeyType;
    import com.alicloud.openservices.tablestore.model.PrimaryKeyValue;
    import com.alicloud.openservices.tablestore.model.RangeRowQueryCriteria;
    import com.alicloud.openservices.tablestore.model.Row;
    import com.alicloud.openservices.tablestore.model.RowPutChange;
    import com.alicloud.openservices.tablestore.model.RowUpdateChange;
    import com.alicloud.openservices.tablestore.model.TableMeta;
    import com.alicloud.openservices.tablestore.model.TableOptions;
    import com.alicloud.openservices.tablestore.model.UpdateRowRequest;
    import com.alicloud.openservices.tablestore.model.search.CreateSearchIndexRequest;
    import com.alicloud.openservices.tablestore.model.search.FieldSchema;
    import com.alicloud.openservices.tablestore.model.search.FieldType;
    import com.alicloud.openservices.tablestore.model.search.IndexSchema;
    import com.alicloud.openservices.tablestore.model.search.vector.VectorDataType;
    import com.alicloud.openservices.tablestore.model.search.vector.VectorMetricType;
    import com.alicloud.openservices.tablestore.model.search.vector.VectorOptions;
    
    import java.util.Arrays;
    import java.util.Collections;
    import java.util.UUID;
    import java.util.stream.Collectors;
    
    public class DashScopeToTableStoreTests {
    
        private static final String DASH_SCOPE_API_KEY = "你的api-key";
    
        public static void main(String[] args) throws Exception {
            // 初始化tableStoreClient。
            SyncClient tableStoreClient = new SyncClient(System.getenv("endPoint"), System.getenv("accessId"), System.getenv("accessKey"), System.getenv("instanceName"));
            // 创建数据表和多元索引。
            {
                createTable(tableStoreClient);
                createSearchIndex(tableStoreClient);
            }
    
            // 方式1:直接写入向量数据到TableStore中。
            {
                batchWriteRow(tableStoreClient);
            }
            // 方式2:将TableStore中存量的数据生成向量再写入到TableStore中。
            {
                getRangeAndUpdateVector(tableStoreClient);
            }
        }
        
        // 文本转向量。
        private static String textToVector(String text) throws Exception {
            TextEmbeddingParam param = TextEmbeddingParam
                    .builder()
                    .model(TextEmbedding.Models.TEXT_EMBEDDING_V2) // V2模型的向量进行了归一化,推荐使用点积(dot_product)进行向量检索。
                    .apiKey(DASH_SCOPE_API_KEY)
                    .texts(Collections.singleton(text)) // 支持同时生成多行,此处使用一行作为示例。实际使用时可考虑单次请求设置多行来减少调用。
                    .build();
            TextEmbedding textEmbedding = new TextEmbedding();
            TextEmbeddingResult result = textEmbedding.call(param);
            // 返回结果转成Tablestore支持的格式,即float32数组字符串。例如[1, 5.1, 4.7, 0.08 ]。
            return result.getOutput().getEmbeddings().get(0).getEmbedding().stream().map(Double::floatValue).collect(Collectors.toList()).toString();
        }
    
        // 创建数据表。
        private static void createTable(SyncClient tableStoreClient) {
            TableMeta tableMeta = new TableMeta("TABLE_NAME");
            tableMeta.addPrimaryKeyColumn(new PrimaryKeySchema("PK_1", PrimaryKeyType.STRING));
            int timeToLive = -1; // 数据的过期时间, 单位秒, -1代表永不过期. 假如设置过期时间为一年, 即为365 * 24 * 3600。
            int maxVersions = 1;
            TableOptions tableOptions = new TableOptions(timeToLive, maxVersions);
            CreateTableRequest request = new CreateTableRequest(tableMeta, tableOptions);
            tableStoreClient.createTable(request);
        }
    
        // 创建多元索引,并指定向量索引字段信息。
        private static void createSearchIndex(SyncClient tableStoreClient) {
            CreateSearchIndexRequest request = new CreateSearchIndexRequest();
            request.setTableName("TABLE_NAME");
            request.setIndexName("INDEX_NAME");
            IndexSchema indexSchema = new IndexSchema();
            indexSchema.setFieldSchemas(Arrays.asList(
                    // 字符串字段,支持文本匹配查询。
                    new FieldSchema("field_string", FieldType.KEYWORD).setIndex(true),
                    // 整型字段,支持数字范围查询
                    new FieldSchema("field_long", FieldType.LONG).setIndex(true),
                    // 全文检索字段。
                    new FieldSchema("field_text", FieldType.TEXT).setIndex(true).setAnalyzer(FieldSchema.Analyzer.MaxWord),
                    // 向量检索字段,使用点积作为距离度量算法,向量维度为1536。
                    new FieldSchema("field_vector", FieldType.VECTOR).setIndex(true).setVectorOptions(new VectorOptions(VectorDataType.FLOAT_32, 1536, VectorMetricType.DOT_PRODUCT))
            ));
            request.setIndexSchema(indexSchema);
            tableStoreClient.createSearchIndex(request);
        }
    
        // 批量写入数据。
        private static void batchWriteRow(SyncClient tableStoreClient) throws Exception {
            // 写入1千行数据,每100行一个批次。
            for (int i = 0; i < 10; i++) {
                BatchWriteRowRequest batchWriteRowRequest = new BatchWriteRowRequest();
                for (int j = 0; j < 100; j++) {
                    // 用户的业务数据。
                    String text = "一段字符串,可用户全文检索。同时该字段生成Embedding向量,写入到下方field_vector字段中进行向量语义相似性查询";
                    // 文本转为向量。
                    String vector = textToVector(text);
                    RowPutChange rowPutChange = new RowPutChange("TABLE_NAME");
                    // 设置主键。
                    rowPutChange.setPrimaryKey(PrimaryKeyBuilder.createPrimaryKeyBuilder().addPrimaryKeyColumn("PK_1", PrimaryKeyValue.fromString(UUID.randomUUID().toString())).build());
                    // 设置属性列。
                    rowPutChange.addColumn("field_string", ColumnValue.fromLong(i));
                    rowPutChange.addColumn("field_long", ColumnValue.fromLong(i * 100 + j));
                    rowPutChange.addColumn("field_text", ColumnValue.fromString(text));
                    // 向量格式为float32数组字符串,例如[1, 5.1, 4.7, 0.08 ]。此处直接使用DashScope生成向量。
                    rowPutChange.addColumn("field_vector", ColumnValue.fromString(vector));
    
                    batchWriteRowRequest.addRowChange(rowPutChange);
                }
                BatchWriteRowResponse batchWriteRowResponse = tableStoreClient.batchWriteRow(batchWriteRowRequest);
                System.out.println("批量写入是否全部成功:" + batchWriteRowResponse.isAllSucceed());
                if (!batchWriteRowResponse.isAllSucceed()) {
                    for (BatchWriteRowResponse.RowResult rowResult : batchWriteRowResponse.getFailedRows()) {
                        System.out.println("失败的行:" + batchWriteRowRequest.getRowChange(rowResult.getTableName(), rowResult.getIndex()).getPrimaryKey());
                        System.out.println("失败原因:" + rowResult.getError());
                    }
                }
            }
        }
    
        // 遍历所有数据, 并更新field_vector向量字段。
        private static void getRangeAndUpdateVector(SyncClient tableStoreClient) throws Exception {
            int total = 0;
            RangeRowQueryCriteria rangeRowQueryCriteria = new RangeRowQueryCriteria("TABLE_NAME");
    
            PrimaryKeyBuilder start = PrimaryKeyBuilder.createPrimaryKeyBuilder();
            start.addPrimaryKeyColumn("PK_1", PrimaryKeyValue.INF_MIN);
            rangeRowQueryCriteria.setInclusiveStartPrimaryKey(start.build());
    
            PrimaryKeyBuilder end = PrimaryKeyBuilder.createPrimaryKeyBuilder();
            end.addPrimaryKeyColumn("PK_1", PrimaryKeyValue.INF_MAX);
            rangeRowQueryCriteria.setExclusiveEndPrimaryKey(end.build());
    
            rangeRowQueryCriteria.setMaxVersions(1);
            rangeRowQueryCriteria.setLimit(5000);
            rangeRowQueryCriteria.addColumnsToGet(Arrays.asList("field_text", "想要返回的其它字段"));
            rangeRowQueryCriteria.setDirection(Direction.FORWARD);
            GetRangeRequest getRangeRequest = new GetRangeRequest(rangeRowQueryCriteria);
            GetRangeResponse getRangeResponse;
            while (true) {
                getRangeResponse = tableStoreClient.getRange(getRangeRequest);
                for (Row row : getRangeResponse.getRows()) {
                    total++;
                    PrimaryKey primaryKey = row.getPrimaryKey();
                    // 获取用户的文本内容。
                    String text = row.getLatestColumn("field_text").getValue().asString();
                    // 文本转为向量。
                    String vector = textToVector(text);
                    // 将向量更新到数据表中。此处用单行更新作为示例,您可以使用batchWriteRow批量执行。
                    {
                        RowUpdateChange rowUpdateChange = new RowUpdateChange("TABLE_NAME");
                        // 设置主键。
                        rowUpdateChange.setPrimaryKey(primaryKey);
                        // 设置需要更新的属性列。
                        rowUpdateChange.put("field_vector", ColumnValue.fromString(vector));
                        // 执行单行更新。
                        tableStoreClient.updateRow(new UpdateRowRequest(rowUpdateChange));
                    }
                }
                if (getRangeResponse.getNextStartPrimaryKey() != null) {
                    rangeRowQueryCriteria.setInclusiveStartPrimaryKey(getRangeResponse.getNextStartPrimaryKey());
                } else {
                    break;
                }
            }
            System.out.println("一共处理数据: " + total);
        }
    }

3.结果验证

表格存储控制台查看写入表格存储中的向量数据。您可以使用数据读取接口(GetRow、BatchGetRow和GetRange)或者使用多元索引的向量检索查询向量数据。

  • 使用数据读取接口查询向量数据

    向量数据写入到表格存储后,您可以直接读取表中的向量数据。具体操作,请参见读取数据

  • 使用向量检索功能查询向量数据

    创建多元索引时配置向量字段后,您可以使用向量检索功能查询向量数据。具体操作,请参见向量检索介绍与使用

计费说明

相关文档

您也可以通过免费开源模型将表格存储中数据转成向量。更多信息,请参见使用免费开源模型将Tablestore表中数据转成向量