検索インデックスを使用すると、プライマリキー以外の列や複数の条件に基づいてデータをクエリできます。このトピックでは、製品データを例として、Tablestore SDK for Java を使用してデータテーブルと検索インデックスを作成し、データを書き込み、Term クエリを実行する方法を説明します。
事前準備
Tablestore を有効化し、インスタンスを作成します。詳細については、「サービスのアクティブ化とインスタンスの作成」をご参照ください。
Tablestore SDK for Java をインストールし、クライアントを初期化して、
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 に設定する必要があります。また、データが期限切れにならないように、データテーブルの Time to Live (TTL) を -1 に設定するか、データ更新を無効にする必要があります。この例では、最大バージョン数は 1 に、TTL は -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));
}
ステップ 2:検索インデックスの作成
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:サンプルデータの書き込み
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));
}
ステップ 4:データのクエリ
term クエリを実行して、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();
次のステップ
検索インデックスの仕組み、ユースケース、制限事項については、「検索インデックス」をご参照ください。
インデックスの並べ替え、TTL、仮想列、およびその他のインデックス機能については、「検索インデックスの作成」をご参照ください。
他のクエリタイプ、およびクエリ結果の並べ替え、集計、または重複排除の方法については、「データクエリ」をご参照ください。