多元索引支持基于非主键列和多个查询条件检索数据。本文以商品数据为例,介绍如何通过 Tablestore 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();
后续步骤
该文章对您有帮助吗?