検索インデックスを使用してデータをクエリする場合、定義済みのソート方法を使用するか、ソート方法を指定できます。このようにして、クエリ条件を満たす行は、事前に定義または指定した順序に基づいて返されます。レスポンスに多数の行が含まれている場合は、limit パラメーターと offset パラメーターを設定するか、トークンを使用して必要なデータを特定できます。
シナリオ
カテゴリ | 方法 | 機能 | シナリオ |
ソート | 検索インデックスの作成時にソート方法を事前定義する | デフォルトでは、検索インデックスのデータは、IndexSort パラメーターで指定された事前ソート設定に基づいてソートされます。IndexSort パラメーターで指定された事前ソート設定により、クエリ条件を満たす行が返されるデフォルトの順序が決まります。 | |
データをクエリするときにソート方法を指定する | ScoreSort を使用して、BM25ベースのキーワード関連性スコアに基づいてクエリ結果をソートできます。ScoreSort は、全文検索などのシナリオに適しています。 | ||
PrimaryKeySort を使用して、主キー値に基づいてクエリ結果をソートできます。PrimaryKeySort は、データの一意の識別子に基づいてデータをソートする場合に適しています。 | |||
FieldSort を使用して、1 つ以上の列の値に基づいてクエリ結果をソートできます。FieldSort は、売上高やページビューなどのプロパティに基づいてデータをソートする場合に適しています。ほとんどの場合、FieldSort は、eコマース、ソーシャルネットワーキング、メディアアセットなどの業界で使用されます。 FieldSort の mode パラメーターを、Array フィールドや Nested フィールドなどの複数値フィールドに指定して、クエリ結果のソートに使用する要素を決定できます。 | |||
GeoDistanceSort を使用して、地理的位置によってクエリ結果をソートできます。GeoDistanceSort は、特定の場所からの距離に基づいてデータをソートする場合に適しています。ほとんどの場合、GeoDistanceSort は、マッピングや物流などの業界で使用されます。たとえば、場所の周りのレストランを、その場所からの距離に基づいてソートできます。 | |||
ページング | データをクエリするときにページング方法を指定する | レスポンスの行数が 100,000 未満の場合、この方法を使用してページにジャンプできます。 | |
この機能を使用すると、データはページごとに返され、後方ページングのみ可能です。前方ページングを行う場合は、トークンはクエリ中に有効であるため、前のトークンをキャッシュして使用できます。 |
Tablestore SDK を使用してソートとページングを実行する
次の Tablestore SDK を使用してソートとページングを実行できます。
インデックスの事前ソート
デフォルトでは、検索インデックスのデータは、IndexSort パラメーターで指定された事前ソート設定に基づいてソートされます。検索インデックスを使用してデータをクエリする場合、IndexSort パラメーターで指定された事前ソート設定により、一致するデータが返されるデフォルトの順序が決まります。
検索インデックスを作成するときに、IndexSort パラメーターを設定することで事前ソート設定を指定できます。事前ソート設定を指定しない場合、検索インデックスのデータは主キー値でソートされます。
検索インデックスの事前ソート方法として、PrimaryKeySort または FieldSort を指定できます。PrimaryKeySort は主キー値でデータをソートし、FieldSort はフィールド値でデータをソートします。
Nested フィールドを含む検索インデックスは、インデックスの事前ソートをサポートしていません。
既存の検索インデックスの IndexSort パラメーターの設定を変更する場合は、検索インデックスのスキーマを動的に変更できます。詳細については、検索インデックスのスキーマを動的に変更するを参照してください。
データをクエリするときにソート方法を指定する
ソートは、enableSortAndAgg パラメーターが true に設定されているフィールドに対してのみ有効にできます。
クエリごとにソート方法を指定できます。検索インデックスベースのクエリは、次のソート方法をサポートしています。優先順位に基づいて複数のソート方法を指定することもできます。
ScoreSort
ScoreSort を使用して、BM25ベースのキーワード関連性スコアに基づいてクエリ結果をソートできます。ScoreSort は、全文検索などのシナリオに適しています。
一致するデータをキーワード関連性スコアでソートする前に、ScoreSort のパラメーターを設定する必要があります。設定しない場合、一致するデータは、IndexSort パラメーターで指定された事前ソート設定に基づいてソートされます。
SearchQuery searchQuery = new SearchQuery();
// BM25ベースのキーワード関連性スコアに基づいてクエリ結果をソートします。
searchQuery.setSort(new Sort(Arrays.asList(new ScoreSort())));
PrimaryKeySort
PrimaryKeySort を使用して、主キー値に基づいてクエリ結果をソートできます。
SearchQuery searchQuery = new SearchQuery();
searchQuery.setSort(new Sort(Arrays.asList(new PrimaryKeySort()))); // クエリ結果を昇順にソートします。
//searchQuery.setSort(new Sort(Arrays.asList(new PrimaryKeySort(SortOrder.DESC)))); // クエリ結果を降順にソートします。
FieldSort
FieldSort を使用して、1 つ以上の特定の列の値に基づいてクエリ結果をソートできます。
単一列の値に基づいてクエリ結果をソートする
FieldSort を使用して、特定の列の値に基づいてクエリ結果をソートできます。
SearchQuery searchQuery = new SearchQuery();
searchQuery.setSort(new Sort(Arrays.asList(new FieldSort("col", SortOrder.ASC))));
複数列の値に基づいてクエリ結果をソートする
特定の順序で2つの列の値に基づいてクエリ結果をソートして、一致するデータが返される順序を決定することもできます。
SearchQuery searchQuery = new SearchQuery();
searchQuery.setSort(new Sort(Arrays.asList(
new FieldSort("col1", SortOrder.ASC), new FieldSort("col2", SortOrder.ASC))));
補助列の値に基づいてクエリ結果をソートする
Long、Double、または Date 型の列値に基づいてデータをソートする場合、missingField パラメーターを設定して、元の列にデータがない場合に使用する同じデータ型の列を補助列として指定できます。
/**
* Col_Long 列の値に基づいてクエリ結果を降順にソートします。Long 型の Col_Long 列のデータがない場合は、同じデータ型の Col_Long_sec 列をソートの補助列として使用できます。
*/
SearchQuery searchQuery = new SearchQuery();
FieldSort fieldSort = new FieldSort("Col_Long");
// Col_Long 列のデータがない場合のソートの補助列として Col_Long_sec 列を指定します。
fieldSort.setMissingField("Col_Long_sec");
fieldSort.setOrder(SortOrder.DESC);
複数値フィールドの指定された要素に基づいてクエリ結果をソートする
Array フィールドや Nested フィールドなどの複数値フィールドに mode パラメーターを指定して、クエリ結果のソートに使用する要素を決定できます。
Array フィールドに mode パラメーターを指定して、クエリ結果のソートに使用する要素を決定できます。
// doc1 行と doc2 行には、Array 型の field1 列が含まれています。doc1 行の field1 列の値は [2,3] で、doc2 行の field1 列の値は [1,3,4] です。
// mode パラメーターを指定して、2 つの行のソートに使用する Array フィールドの要素を決定できます。
{
// mode パラメーターを SortMode.MAX に設定すると、Array フィールドの最大要素を使用して行がソートされます。この例では、doc1 行の 3 と doc2 行の 4 を使用して 2 つの行がソートされ、ソート結果は doc2 と doc1 になります。
FieldSort fieldSort = new FieldSort("field1", SortOrder.DESC);
fieldSort.setMode(SortMode.MAX);
}
{
// mode パラメーターを SortMode.MIN に設定すると、Array フィールドの最小要素を使用して行がソートされます。この例では、doc1 行の 2 と doc2 行の 1 を使用して 2 つの行がソートされ、ソート結果は doc1 と doc2 になります。
FieldSort fieldSort = new FieldSort("field1", SortOrder.DESC);
fieldSort.setMode(SortMode.MIN);
}
Nested フィールドに mode パラメーターを指定して、子行のソートに使用する要素を決定することもできます。
// doc1 行と doc2 行には、Nested 型の field1 列が含まれています。
// doc1 行の field1 列の値は [{"name":"b", "age":1},{"name":"a", "age":7}] です。
// doc2 行の field1 列の値は [{"name":"a", "age":1},{"name":"c", "age":1},{"name":"d", "age":5}] です。
{
// mode パラメーターを指定して、2 つの行の子行のソートに使用する Nested フィールドの要素を決定できます。
// mode パラメーターを SortMode.MAX に設定すると、Nested フィールドの最大要素を使用して行がソートされます。この例では、doc1 行の 7 と doc2 行の 5 を使用して age 列で 2 つの行がソートされ、ソート結果は doc1 と doc2 になります。
FieldSort fieldSort = new FieldSort("field1.age", SortOrder.DESC);
fieldSort.setMode(SortMode.MAX);
String path = "field1";
NestedFilter nestedFilter = new NestedFilter(path, QueryBuilders.matchAll().build());
fieldSort.setNestedFilter(nestedFilter);
}
{
// mode パラメーターを指定して、age 列の値が 1 である子行のソートに使用する Nested フィールドの要素を決定できます。
{
// mode パラメーターを SortMode.MAX に設定すると、Nested フィールドの最大要素を使用して行がソートされます。この例では、doc1 行の「b」と doc2 行の「a」を使用して name 列で 2 つの行がソートされ、ソート結果は doc2 と doc1 になります。
FieldSort fieldSort = new FieldSort("field1.name", SortOrder.DESC);
fieldSort.setMode(SortMode.MAX);
String path = "field1";
NestedFilter nestedFilter = new NestedFilter(path, QueryBuilders.term("students.age",1).build());
fieldSort.setNestedFilter(nestedFilter);
}
{
// mode パラメーターを SortMode.MIN に設定すると、Nested フィールドの最小要素を使用して行がソートされます。この例では、doc1 行の「b」と doc2 行の「a」を使用して name 列で 2 つの行がソートされ、ソート結果は doc1 と doc2 になります。
FieldSort fieldSort = new FieldSort("field1.name", SortOrder.DESC);
fieldSort.setMode(SortMode.MIN);
String path = "field1";
NestedFilter nestedFilter = new NestedFilter(path, QueryBuilders.term("students.age",1).build());
fieldSort.setNestedFilter(nestedFilter);
}
}
GeoDistanceSort
GeoDistanceSort を使用して、地理的位置によってクエリ結果をソートできます。
SearchQuery searchQuery = new SearchQuery();
// GEOPOINT geo 列の値から座標ペア (0, 0) までの距離に基づいて結果をソートします。
Sort.Sorter sorter = new GeoDistanceSort("geo", Arrays.asList("0, 0"));
searchQuery.setSort(new Sort(Arrays.asList(sorter)));
ページング方法を指定する
limit パラメーターと offset パラメーターを設定するか、トークンを使用してレスポンスの行をページングできます。
limit パラメーターと offset パラメーターを設定する
レスポンスの行の合計数が 100,000 未満の場合、limit パラメーターと offset パラメーターを設定して行をページングできます。limit パラメーターと offset パラメーターの値の合計は 100,000 を超えることはできません。limit パラメーターの最大値は 100 です。
limit パラメーターの最大値を増やす方法については、検索インデックス機能の Search オペレーションを呼び出してデータをクエリするときに、limit パラメーターの値を 1000 に増やすにはどうすればよいですか?を参照してください。
limit パラメーターと offset パラメーターの値を指定しない場合、デフォルト値が使用されます。limit パラメーターのデフォルト値は 10 です。offset パラメーターのデフォルト値は 0 です。
SearchQuery searchQuery = new SearchQuery();
searchQuery.setQuery(new MatchAllQuery());
searchQuery.setLimit(100);
searchQuery.setOffset(100);
トークンを使用する
この方法にはページングの深さに制限がないため、ディープページングにはトークンを使用することをお勧めします。
Tablestore がクエリ条件を満たすすべてのデータを読み取れない場合、Tablestore は nextToken を返します。nextToken を使用して、後続のデータの読み取りを続行できます。
デフォルトでは、トークンを使用する場合、後方ページングのみ可能です。ただし、トークンはクエリ中に有効であるため、前のトークンをキャッシュして使用することで前方ページングを行うことができます。
nextToken を永続化したり、フロントエンドページに転送したりする場合は、Base64 を使用して nextToken を文字列にエンコードできます。トークンは文字列ではありません。new String(nextToken)
を使用してトークンを文字列にエンコードすると、トークンに関する情報が失われます。
トークンを使用する場合、ソート方法は前のリクエストで使用された方法と同じです。Tablestore は、デフォルトでは IndexSort パラメーターに基づいて、または指定した方法に基づいてデータをソートします。トークンを使用する場合、ソート方法を指定することはできません。トークンを使用する場合、offset パラメーターを設定することはできません。データはページごとに順番に返されます。これにより、クエリが遅くなります。
Nested フィールドを含む検索インデックスは、IndexSort をサポートしていません。ページングが必要で、Nested フィールドを含む検索インデックスを使用してデータをクエリする場合は、クエリ条件でソート方法を指定して、指定された順序でデータを返す必要があります。指定しない場合、クエリ条件を満たすデータの一部のみが返されるときに、Tablestore は nextToken を返しません。
private static void readMoreRowsWithToken(SyncClient client) {
SearchQuery searchQuery = new SearchQuery();
searchQuery.setQuery(new MatchAllQuery());
searchQuery.setGetTotalCount(true);// クエリ条件を満たす行の合計数を返すように指定します。
// データテーブルの名前を指定します。例:sampleTable。次に、検索インデックスの名前を指定します。例:sampleSearchIndex。検索インデックスの名前を取得するには、Tablestore コンソールで、または Tablestore SDK を使用して検索インデックスのリストをクエリします。Tablestore コンソールで検索インデックスのリストをクエリする場合は、「テーブルの管理」ページの「インデックス」タブでリストを表示できます。
SearchRequest searchRequest = new SearchRequest("sampleTable", "sampleSearchIndex", searchQuery);
SearchResponse resp = client.search(searchRequest);
if (!resp.isAllSuccess()) {
throw new RuntimeException("not all success"); // 全て成功ではありません
}
List<Row> rows = resp.getRows();
while (resp.getNextToken()!=null) { // レスポンスの nextToken 値が null の場合、すべてのデータが読み取られます。
// nextToken 値をクエリします。
byte[] nextToken = resp.getNextToken();
{
// nextToken を永続化したり、フロントエンドページに転送したりする場合は、Base64 を使用して nextToken を文字列にエンコードできます。
// トークンは文字列ではありません。new String(nextToken) を使用してトークンを文字列にエンコードすると、トークンに関する情報が失われます。
String tokenAsString = Base64.toBase64String(nextToken);
// 文字列をバイトにデコードします。
byte[] tokenAsByte = Base64.fromBase64String(tokenAsString);
}
// このリクエストのトークンを前のレスポンスの nextToken 値に設定します。
searchRequest.getSearchQuery().setToken(nextToken);
resp = client.search(searchRequest);
if (!resp.isAllSuccess()) {
throw new RuntimeException("not all success"); // 全て成功ではありません
}
rows.addAll(resp.getRows());
}
System.out.println("RowSize: " + rows.size());
System.out.println("TotalCount: " + resp.getTotalCount());// 返された行数ではなく、クエリ条件を満たす行の合計数を表示するように指定します。
}