本文中含有需要您注意的重要提示信息,忽略該信息可能對您的業務造成影響,請務必仔細閱讀。
本文以文本數據為例介紹如何將存儲在 Tablestore 中的數據通過阿里云大模型服務平臺百煉生成向量并寫入到表格存儲的數據表中。
方案概覽
阿里云的大模型服務平臺百煉(以下簡稱“百煉”)是一站式的大模型開發及應用構建平臺。百煉提供了多種向量模型,可以將文本、圖像、語音等轉換成向量。更多信息,請參見什么是百煉。
本文使用的是百煉中的文本向量模型 text-embedding-v2,通過模型將存儲在表格存儲中的文本數據生成向量并寫入到表格存儲中只需要 3 步:
開通模型調用服務并獲取 API-KEY :在百煉控制臺開通模型調用服務并獲取 API-KEY。
生成向量并寫入到表格存儲:使用 Java SDK 生成向量數據并寫入到表格存儲的數據表中。
結果驗證:使用表格存儲的數據讀取接口或者多元索引向量檢索功能查詢數據。
使用說明
開發語言:Java
Java 版本:Java 8 及以上版本。
注意事項
Tablestore 多元索引中向量檢索字段的維度、類型和距離算法必須與百煉中的文本向量模型保持一致。例如本文使用百煉的文本向量模型 text-embedding-v2 生成向量,在 Tablestore 中創建多元索引時必須設置向量為 1536 維、FLOAT_32 類型和 DOT_PRODUCT 點積距離算法。
前提條件
使用阿里云賬號或者具有表格存儲和百煉操作權限的 RAM 用戶進行操作。
如果要使用 RAM 用戶進行操作,您需要使用阿里云賬號創建 RAM 用戶并授予 RAM 用戶訪問表格存儲(AliyunOTSFullAccess)以及管理和使用阿里云百煉的權限。具體操作,請參見為 RAM 用戶授予表格存儲操作權限和為 RAM 用戶授予百煉操作權限。
已為阿里云賬號或者 RAM 用戶創建 AccessKey。具體操作,請參見創建 AccessKey。
警告阿里云賬號 AccessKey 泄露會威脅您所有資源的安全。建議您使用 RAM 用戶 AccessKey 進行操作,可以有效降低 AccessKey 泄露的風險。
1. 開通模型調用服務并獲取 API-KEY
在百煉控制臺開通模型調用服務并獲取 API-KEY。
建議您把 API-KEY 配置到環境變量,從而避免在代碼里顯式地配置 API-KEY ,降低泄漏風險。
1.1 開通模型調用服務
前往百煉控制臺,如果頁面頂部顯示以下消息,您需要開通百煉的模型調用服務,以獲得免費額度。如果未顯示該消息,則表示您已經開通服務。
1.2 獲取調用API所需憑證
在百煉控制臺的右上角選擇 API-KEY,然后在我的API-KEY 頁面創建 API-KEY。
2. 生成向量并寫入到表格存儲
通過 Java SDK 使用百煉模型生成向量,并將數據寫入到表格存儲的數據表中。具體步驟如下:
此處以百煉中的文本向量模型 text-embedding-v2 為例介紹向量的生成,其它模型請參見模型列表。
安裝 DashScope Java SDK 和表格存儲 Java SDK。
要在 Maven 工程中使用 DashScope SDK 和表格存儲 SDK 時,您只需在 pom.xml 文件中加入如下依賴:
<!--安裝 DashScope Java SDK --> <dependency> <groupId>com.alibaba</groupId> <artifactId>dashscope-sdk-java</artifactId> <!-- 請根據實際替換為查詢到的最新版本號:https://mvnrepository.com/artifact/com.alibaba/dashscope-sdk-java --> <version>最新版本</version> </dependency> <!--安裝表格存儲 Java SDK --> <dependency> <groupId>com.aliyun.openservices</groupId> <artifactId>tablestore</artifactId> <!-- 請根據實際替換為查詢到的最新版本號 --> <version>最新版本</version> </dependency>
生成向量并將向量數據寫入表格存儲中。
說明使用表格存儲功能前,需要初始化 OTSClient。具體操作,請參見初始化 OTSClient。
建議將 AccessKey(包括 AccessKey ID 和 AccessKey Secret)、實例名稱和實例的服務地址配置到環境變量中。
以下示例介紹了直接將文本模型生成的向量數據寫入表格存儲,以及將表格存儲中存量的數據生成向量后再將向量數據寫入到表格存儲中兩種方式。
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 數據轉成向量。