全部產品
Search
文件中心

Tablestore:多元索引快速入門

更新時間:Jul 31, 2026

多元索引支援基於非主鍵列和多個查詢條件檢索資料。本文以商品資料為例,介紹如何通過 Tablestore Java SDK 建立資料表和多元索引、寫入資料並完成一次精確查詢。

準備工作

  • 已開通 Tablestore 服務並建立執行個體。具體操作,請參見開通服務和建立執行個體。

  • 已安裝 Tablestore Java SDK、初始化用戶端並獲得 SyncClient 執行個體。具體操作,請參見Java SDK。

操作步驟

本樣本建立名稱為 example_table 的資料表和名稱為 example_index 的多元索引。索引就緒後,寫入 3 條商品資料,再查詢 category 列值為 books 的商品。

將各步驟的樣本方法添加到已初始化用戶端的 Java 程式中,然後按以下順序調用:

private static void runQuickStart(SyncClient client)
        throws InterruptedException {
    String tableName = "example_table";
    String indexName = "example_index";

    createTable(client, tableName);
    createSearchIndex(client, tableName, indexName);
    waitUntilSearchIndexIsReady(client, tableName, indexName);
    putSampleRows(client, tableName);

    SearchResponse response =
            waitUntilBooksAreQueryable(client, tableName, indexName);
    System.out.println("Total count: " + response.getTotalCount());
    System.out.println("Rows: " + response.getRows());
}

步驟一:建立資料表

多元索引要求資料表的最大版本數為 1,並且資料生命週期為 -1(資料永不到期)或禁止更新資料。本樣本將最大版本數設定為 1,將資料生命週期設定為 -1。

private static void createTable(
        SyncClient client, String tableName) {
    TableMeta tableMeta = new TableMeta(tableName);
    tableMeta.addPrimaryKeyColumn(
            new PrimaryKeySchema(
                    "product_id", PrimaryKeyType.STRING));

    TableOptions tableOptions = new TableOptions();
    tableOptions.setTimeToLive(-1);
    tableOptions.setMaxVersions(1);

    client.createTable(
            new CreateTableRequest(tableMeta, tableOptions));
}

步驟二:建立多元索引

為 category 和 price 屬性列建立索引欄位。索引欄位的名稱和資料類型必須與資料表中對應屬性列保持一致。

private static void createSearchIndex(
        SyncClient client, String tableName, String indexName) {
    IndexSchema indexSchema = new IndexSchema();
    indexSchema.setFieldSchemas(Arrays.asList(
            new FieldSchema("category", FieldType.KEYWORD),
            new FieldSchema("price", FieldType.LONG)));

    CreateSearchIndexRequest request =
            new CreateSearchIndexRequest();
    request.setTableName(tableName);
    request.setIndexName(indexName);
    request.setIndexSchema(indexSchema);
    client.createSearchIndex(request);
}

建立多元索引為非同步作業。等待索引狀態變為 RUNNING 且同步階段變為 INCR 後,再查詢資料。

private static final int RETRY_ATTEMPTS = 90;
private static final long RETRY_INTERVAL_MILLIS = 1_000L;

private static void waitUntilSearchIndexIsReady(
        SyncClient client, String tableName, String indexName)
        throws InterruptedException {
    for (int attempt = 1; attempt <= RETRY_ATTEMPTS; attempt++) {
        DescribeSearchIndexRequest request =
                new DescribeSearchIndexRequest();
        request.setTableName(tableName);
        request.setIndexName(indexName);
        request.setIncludeSyncStat(true);

        DescribeSearchIndexResponse response =
                client.describeSearchIndex(request);
        if (response.getIndexStatus() != null
                && response.getIndexStatus().indexStatusEnum
                == DescribeSearchIndexResponse.IndexStatusEnum.RUNNING
                && response.getSyncStat() != null
                && response.getSyncStat().getSyncPhase()
                == SyncStat.SyncPhase.INCR) {
            return;
        }
        Thread.sleep(RETRY_INTERVAL_MILLIS);
    }
    throw new IllegalStateException(
            "Search index did not become ready before timeout.");
}

步驟三:寫入樣本資料

寫入 3 條商品資料。其中,product_id 為主鍵列,category 和 price 為屬性列。

private static void putSampleRows(
        SyncClient client, String tableName) {
    putProduct(client, tableName, "product-001", "books", 89L);
    putProduct(client, tableName, "product-002", "books", 129L);
    putProduct(client, tableName, "product-003", "devices", 599L);
}

private static void putProduct(
        SyncClient client,
        String tableName,
        String productId,
        String category,
        long price) {
    PrimaryKey primaryKey =
            PrimaryKeyBuilder.createPrimaryKeyBuilder()
                    .addPrimaryKeyColumn(
                            "product_id",
                            PrimaryKeyValue.fromString(productId))
                    .build();

    RowPutChange rowPutChange =
            new RowPutChange(tableName, primaryKey);
    rowPutChange.addColumn(
            "category", ColumnValue.fromString(category));
    rowPutChange.addColumn(
            "price", ColumnValue.fromLong(price));
    client.putRow(new PutRowRequest(rowPutChange));
}

步驟四:查詢資料

使用精確查詢匹配 category 列值為 books 的商品。由於資料同步到多元索引需要一定時間,樣本會在結果未就緒時重試查詢。

private static SearchResponse waitUntilBooksAreQueryable(
        SyncClient client, String tableName, String indexName)
        throws InterruptedException {
    for (int attempt = 1; attempt <= RETRY_ATTEMPTS; attempt++) {
        SearchResponse response =
                queryBooks(client, tableName, indexName);
        if (response.isAllSuccess()
                && response.getTotalCount() == 2L
                && response.getRows().size() == 2) {
            return response;
        }
        Thread.sleep(RETRY_INTERVAL_MILLIS);
    }
    throw new IllegalStateException(
            "Sample rows were not queryable before timeout.");
}

private static SearchResponse queryBooks(
        SyncClient client, String tableName, String indexName) {
    TermQuery termQuery = new TermQuery();
    termQuery.setFieldName("category");
    termQuery.setTerm(ColumnValue.fromString("books"));

    SearchQuery searchQuery = new SearchQuery();
    searchQuery.setQuery(termQuery);
    searchQuery.setLimit(10);
    searchQuery.setTrackTotalCount(
            SearchQuery.TRACK_TOTAL_COUNT);

    SearchRequest.ColumnsToGet columnsToGet =
            new SearchRequest.ColumnsToGet();
    columnsToGet.setReturnAll(true);

    SearchRequest request =
            new SearchRequest(tableName, indexName, searchQuery);
    request.setColumnsToGet(columnsToGet);
    return client.search(request);
}

程式返回的總行數和結果行數均為 2,表示查詢成功。

清理資源

如果不再需要樣本資源,請先刪除多元索引,再刪除資料表。

DeleteSearchIndexRequest deleteIndexRequest =
        new DeleteSearchIndexRequest();
deleteIndexRequest.setTableName("example_table");
deleteIndexRequest.setIndexName("example_index");
client.deleteSearchIndex(deleteIndexRequest);

client.deleteTable(new DeleteTableRequest("example_table"));
client.shutdown();

後續步驟

  • 如需瞭解多元索引的工作方式、適用情境和使用限制,請參見多元索引。

  • 如需配置索引排序、生命週期、虛擬列等能力,請參見建立多元索引。

  • 如需使用其他查詢方式或對查詢結果排序、彙總和去重,請參見資料查詢。