多元索引快速入门

更新时间:
复制 MD 格式

多元索引支持基于非主键列和多个查询条件检索数据。本文以商品数据为例,介绍如何通过 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));
}

步骤二:创建多元索引

categoryprice 属性列创建索引字段。索引字段的名称和数据类型必须与数据表中对应属性列保持一致。

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 为主键列,categoryprice 为属性列。

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();

后续步骤

  • 如需了解多元索引的工作方式、适用场景和使用限制,请参见多元索引

  • 如需配置索引排序、生命周期、虚拟列等能力,请参见创建多元索引

  • 如需使用其他查询方式或对查询结果排序、聚合和去重,请参见数据查询