本文以文本数据转换成向量为例介绍如何将存储在Tablestore中的文本数据通过阿里云模型服务灵积(DashScope)生成向量。
方案概览
阿里云模型服务灵积(DashScope)提供多种非结构化/结构化数据转换成向量数据的模型服务,可以将文本、语音、图片等转换成向量。更多信息,请参见模型服务灵积简介。
使用DashScope将存储在Tablestore中的文本数据生成向量只需3步:
开通服务并获取API-KEY:DashScope通过API-KEY进行调用鉴权和计量计费。使用DashScope前,您需要开通模型服务灵积DashScope并获取API-KEY。
生成向量并写入到表格存储:使用DashScope生成向量后,将向量数据写入到表格存储数据表中存储。
结果验证:使用表格存储的数据读取接口或者多元索引向量检索功能查询数据。
使用说明
开发语言: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模型服务灵积控制台,在总览页面单击未开通,根据界面提示完成服务开通。
1.2 获取调用API所需凭证
在DashScope控制台的API-KEY管理页面,单击创建新的API-KEY来创建API-KEY用于调用API。
2. 生成向量并写入到表格存储
使用模型服务进行向量生成后,将向量写入到表格存储数据表中。具体步骤如下:
安装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>
生成向量并将向量写入表格存储中。
以下示例使用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)或者使用多元索引的向量检索查询向量数据。
计费说明
使用模型服务灵积时,在调用API后将产生计量和计费。更多信息,请参见模型服务灵积产品计费。
使用表格存储时,数据表和多元索引的数据量会占用存储空间,直接读写表中数据和使用多元索引向量检索功能查询数据会消耗计算资源。其中在VCU模式(原预留模式)下,计算资源消耗会按照计算能力计费,在CU模式(原按量模式)下,计算资源消耗会按照读吞吐量和写吞吐量计费。更多信息,请参见表格存储产品计费。
相关文档
您也可以通过免费开源模型将表格存储中数据转成向量。更多信息,请参见使用免费开源模型将Tablestore表中数据转成向量。