ネストクエリを実行して、ネストフィールドの子行のデータをクエリできます。ネストフィールドは直接クエリできません。ネストフィールドをクエリするには、NestedQuery オブジェクトでネストフィールドのパスとサブクエリを指定する必要があります。サブクエリは任意のタイプのクエリにすることができます。
前提条件
OTSClient インスタンスが初期化されていること。詳細については、OTSClient インスタンスの初期化を参照してください。
データテーブルが作成され、データがデータテーブルに書き込まれていること。詳細については、データテーブルの作成とデータの書き込みを参照してください。
データテーブルの検索インデックスが作成されていること。詳細については、検索インデックスの作成を参照してください。
パラメータ
パラメータ | 説明 |
path | ネストフィールドのパス。パスはツリー構造に似ています。たとえば、news.title は、news という名前のネストフィールド内の title サブフィールドを示します。 |
query | ネストフィールドのサブフィールドで実行するクエリ。クエリは任意のクエリタイプにすることができます。 |
scoreMode | フィールドに複数の値が含まれている場合にスコアを計算するために使用される値。 |
getTotalCount | クエリ条件を満たす行の総数を返すかどうかを指定します。このパラメータのデフォルト値は false で、クエリ条件を満たす行の総数は返されません。 このパラメータを true に設定すると、クエリのパフォーマンスが低下します。 |
weight | BM25 ベースのキーワード関連性スコアを計算するために、クエリ対象のフィールドに割り当てる重み。このパラメータは、全文検索シナリオで使用されます。クエリ対象のフィールドに高い重みを指定すると、そのフィールドの BM25 ベースのキーワード関連性スコアが高くなります。このパラメータの値は正の浮動小数点数です。 このパラメータは、返される行の数には影響しません。ただし、このパラメータは、クエリ結果の BM25 ベースのキーワード関連性スコアに影響します。 |
tableName | データテーブルの名前。 |
indexName | 検索インデックスの名前。 |
columnsToGet | クエリ条件を満たす各行のすべての列を返すかどうかを指定します。このパラメータには、returnAll パラメータと columns パラメータを設定できます。 returnAll パラメータのデフォルト値は false で、すべての列が返されるわけではないことを指定します。この場合、columns パラメータを使用して、返す列を指定できます。返す列を指定しない場合は、プライマリキー列のみが返されます。 returnAll パラメータを true に設定すると、すべての列が返されます。 |
InnerHits | ネストフィールドのサブフィールドの設定。
|
例
次の例は、ネストクエリを実行する方法を示しています。
単一レベルのネストフィールドのクエリ
次のサンプルコードは、col_nested.nested_1 列の値が tablestore である行をクエリする方法の例を示しています。この例では、col_nested という名前のネスト列には、nested_1 と nested_2 のサブ列が含まれています。
private static void nestedQuery(SyncClient client) {
SearchQuery searchQuery = new SearchQuery();
NestedQuery nestedQuery = new NestedQuery(); // クエリタイプを NestedQuery に設定します。
nestedQuery.setPath("col_nested"); // ネスト列のパスを指定します。
TermQuery termQuery = new TermQuery(); // ネストクエリを実行するためのサブクエリを指定します。
termQuery.setFieldName("col_nested.nested_1"); // 列の名前を指定します。名前には、ネスト列のパスを含める必要があります。
termQuery.setTerm(ColumnValue.fromString("tablestore")); // 列値の照合に使用する値を指定します。
nestedQuery.setQuery(termQuery);
nestedQuery.setScoreMode(ScoreMode.None);
searchQuery.setQuery(nestedQuery);
//searchQuery.setGetTotalCount(true);// GetTotalCount パラメータを true に設定して、一致する行の総数を返します。
SearchRequest searchRequest = new SearchRequest("<TABLE_NAME>", "<SEARCH_INDEX_NAME>", searchQuery);
// columnsToGet パラメータを設定して、返す列を指定するか、すべての列を返すように指定できます。このパラメータを設定しない場合は、プライマリキー列のみが返されます。
//SearchRequest.ColumnsToGet columnsToGet = new SearchRequest.ColumnsToGet();
//columnsToGet.setReturnAll(true); // すべての列を返すように指定します。
//columnsToGet.setColumns(Arrays.asList("ColName1","ColName2")); // 返す列を指定します。
//searchRequest.setColumnsToGet(columnsToGet);
SearchResponse resp = client.search(searchRequest);
//System.out.println("TotalCount: " + resp.getTotalCount()); // 返される行の数ではなく、一致する行の総数を表示するように指定します。
System.out.println("Row: " + resp.getRows());
}
複数レベルのネストフィールドのクエリ
次のサンプルコードは、col_nested.nested_2.nested_2_2 列の値が tablestore である行をクエリする方法の例を示しています。この例では、col_nested という名前のネスト列には、nested_1 と nested_2 のサブ列が含まれています。 nested_2 サブ列には、nested_2_1 列と nested_2_2 列が含まれています。
private static void nestedQuery(SyncClient client) {
SearchQuery searchQuery = new SearchQuery();
NestedQuery nestedQuery = new NestedQuery(); // クエリタイプを NestedQuery に設定します。
nestedQuery.setPath("col_nested.nested_2"); // ネスト列のパスを指定します。これは、クエリ対象の列の親パスです。
TermQuery termQuery = new TermQuery(); // ネストクエリを実行するためのサブクエリを指定します。
termQuery.setFieldName("col_nested.nested_2.nested_2_2"); // 列の名前を指定します。名前には、ネスト列のパスを含める必要があります。
termQuery.setTerm(ColumnValue.fromString("tablestore")); // 列値の照合に使用する値を指定します。
nestedQuery.setQuery(termQuery);
nestedQuery.setScoreMode(ScoreMode.None);
searchQuery.setQuery(nestedQuery);
//searchQuery.setGetTotalCount(true);// GetTotalCount パラメータを true に設定して、一致する行の総数を返します。
SearchRequest searchRequest = new SearchRequest("<TABLE_NAME>", "<SEARCH_INDEX_NAME>", searchQuery);
// columnsToGet パラメータを設定して、返す列を指定するか、すべての列を返すように指定できます。このパラメータを設定しない場合は、プライマリキー列のみが返されます。
//SearchRequest.ColumnsToGet columnsToGet = new SearchRequest.ColumnsToGet();
//columnsToGet.setReturnAll(true); // すべての列を返すように指定します。
//columnsToGet.setColumns(Arrays.asList("ColName1","ColName2")); // 返す列を指定します。
//searchRequest.setColumnsToGet(columnsToGet);
SearchResponse resp = client.search(searchRequest);
//System.out.println("TotalCount: " + resp.getTotalCount()); // 返される行の数ではなく、一致する行の総数を表示するように指定します。
System.out.println("Row: " + resp.getRows());
}
ネストクエリとブールクエリを組み合わせる
クエリ要件
次のサンプルコードは、クエリ要件に基づいてデータをクエリする方法の例を示しています。クエリ要件に基づいて、対応するサンプルコードを参照してください。
同じ子行が複数のクエリ条件を満たす
次のサンプルコードは、col_nested.col_keyword
列の値が "tablestore" で、col_nested.col_long
列の値が空でない行をクエリする方法の例を示しています。 col_nested.col_keyword 列と col_nested.col_long 列は同じ子行に属しています。
データテーブルのサンプル行に基づくと、シリアル番号が 2 の行のみがクエリ条件を満たします。
public static void nestedQuery(SyncClient client) {
// クエリ条件 1: col_nested 列の子行の col_keyword 列の値が "tablestore" である。
TermQuery termQuery = new TermQuery();
termQuery.setFieldName("col_nested.col_keyword");
termQuery.setTerm(ColumnValue.fromString("tablestore"));
// クエリ条件 2: col_nested 列の子行の col_long 列の値が空でない。
ExistsQuery existsQuery = new ExistsQuery();
existsQuery.setFieldName("col_nested.col_long");
// ブールクエリの And 演算子を使用して、子行が上記の 2 つのクエリ条件を同時に満たす行をクエリします。
List<Query> mustQueries = new ArrayList<>();
mustQueries.add(termQuery);
mustQueries.add(existsQuery);
BoolQuery boolQuery = new BoolQuery();
boolQuery.setMustQueries(mustQueries);
// ネストクエリで複数のブールクエリを指定して、子行が上記の 2 つのクエリ条件を同時に満たす行をクエリします。
NestedQuery nestedQuery = new NestedQuery(); // クエリタイプを NestedQuery に設定します。
nestedQuery.setPath("col_nested"); // ネスト列のパスを指定します。これは、クエリ対象の列の親パスです。
nestedQuery.setQuery(boolQuery);
nestedQuery.setScoreMode(ScoreMode.None);
SearchQuery searchQuery = new SearchQuery();
searchQuery.setQuery(nestedQuery);
SearchRequest searchRequest = new SearchRequest("<TABLE_NAME>", "<SEARCH_INDEX_NAME>", searchQuery);
// columnsToGet パラメータを設定して、返す列を指定するか、すべての列を返すように指定できます。このパラメータを設定しない場合は、プライマリキー列のみが返されます。
//SearchRequest.ColumnsToGet columnsToGet = new SearchRequest.ColumnsToGet();
//columnsToGet.setReturnAll(true); // すべての列を返すように指定します。
//columnsToGet.setColumns(Arrays.asList("ColName1","ColName2")); // 返す列を指定します。
//searchRequest.setColumnsToGet(columnsToGet);
SearchResponse resp = client.search(searchRequest);
//System.out.println("TotalCount: " + resp.getTotalCount()); // 返される行の数ではなく、一致する行の総数を表示するように指定します。
System.out.println("Row: " + resp.getRows());
}
異なる子行が複数のクエリ条件を満たす
次のサンプルコードは、col_nested.col_keyword
列の値が "tablestore" で、col_nested.col_long
列の値が空でない行をクエリする方法の例を示しています。 col_nested.col_keyword 列と col_nested.col_long 列は、同じ子行または異なる子行に属しています。
データテーブルのサンプル行に基づくと、シリアル番号が 1 と 2 の行がクエリ条件を満たします。
public static void nestedQuery(SyncClient client) {
// クエリ条件 1: col_nested 列の子行の col_keyword 列の値が "tablestore" である。
TermQuery termQuery = new TermQuery();
termQuery.setFieldName("col_nested.col_keyword");
termQuery.setTerm(ColumnValue.fromString("tablestore"));
NestedQuery nestedTermQuery = new NestedQuery();
nestedTermQuery.setPath("col_nested");
nestedTermQuery.setScoreMode(ScoreMode.None);
nestedTermQuery.setQuery(termQuery);
// クエリ条件 2: col_nested 列の子行の col_long 列の値が空でない。
ExistsQuery existsQuery = new ExistsQuery();
existsQuery.setFieldName("col_nested.col_long");
NestedQuery nestedExistsQuery = new NestedQuery();
nestedExistsQuery.setPath("col_nested");
nestedExistsQuery.setScoreMode(ScoreMode.None);
nestedExistsQuery.setQuery(existsQuery);
// ブールクエリの And 演算子を使用して、上記の 2 つのクエリ条件を満たす行をクエリします。
List<Query> mustQueries = new ArrayList<>();
mustQueries.add(nestedTermQuery);
mustQueries.add(nestedExistsQuery);
// ブールクエリで複数のネストクエリを指定して、子行がクエリ条件を満たす行をクエリします。
BoolQuery boolQuery = new BoolQuery();
boolQuery.setMustQueries(mustQueries);
SearchQuery searchQuery = new SearchQuery();
searchQuery.setQuery(boolQuery);
SearchRequest searchRequest = new SearchRequest("<TABLE_NAME>", "<SEARCH_INDEX_NAME>", searchQuery);
// columnsToGet パラメータを設定して、返す列を指定するか、すべての列を返すように指定できます。このパラメータを設定しない場合は、プライマリキー列のみが返されます。
//SearchRequest.ColumnsToGet columnsToGet = new SearchRequest.ColumnsToGet();
//columnsToGet.setReturnAll(true); // すべての列を返すように指定します。
//columnsToGet.setColumns(Arrays.asList("ColName1","ColName2")); // 返す列を指定します。
//searchRequest.setColumnsToGet(columnsToGet);
SearchResponse resp = client.search(searchRequest);
//System.out.println("TotalCount: " + resp.getTotalCount()); // 返される行の数ではなく、一致する行の総数を表示するように指定します。
System.out.println("Row: " + resp.getRows());
}
ネストクエリでハイライト機能を使用する
次のサンプルコードは、ネストクエリを使用して、Col_Nested という名前のネスト列の Level1_Col1_Nested サブ列の値が hangzhou shanghai
と一致する行をクエリし、クエリ結果でクエリ文字列をハイライトする方法の例を示しています。
/**
* ネストクエリの innerHits パラメータを使用してハイライト機能を有効にします。
*/
public static void nestedQueryWithHighlighting(SyncClient client) {
SearchRequest searchRequest = SearchRequest.newBuilder()
.tableName("<TABLE_NAME>")
.indexName("<SEARCH_INDEX_NAME>")
.returnAllColumnsFromIndex(true)
.searchQuery(SearchQuery.newBuilder()
.limit(5)
.query(QueryBuilders.nested()
.path("Col_Nested")
.scoreMode(ScoreMode.Min)
.query(QueryBuilders.match("Col_Nested.Level1_Col1_Nested", "hangzhou shanghai"))
.innerHits(InnerHits.newBuilder()
.highlight(Highlight.newBuilder()
.addFieldHighlightParam("Col_Nested.Level1_Col1_Nested", HighlightParameter.newBuilder().build())
.build())
.build()))
.build())
.build();
SearchResponse resp = client.search(searchRequest);
// ハイライトされた結果を表示します。
printSearchHit(resp.getSearchHits(), "");
}
/**
* クエリ条件を満たすコンテンツを表示します。
* @param searchHits searchHits
* 出力が @param prefix Nested 構造を使用する場合は、プレフィックスを追加して階層情報を表示します。
*/
private static void printSearchHit(List<SearchHit> searchHits, String prefix) {
for (SearchHit searchHit : searchHits) {
if (searchHit.getScore() != null) {
System.out.printf("%s Score: %s\n", prefix, searchHit.getScore());
}
if (searchHit.getOffset() != null) {
System.out.printf("%s Offset: %s\n", prefix, searchHit.getOffset());
}
if (searchHit.getRow() != null) {
System.out.printf("%s Row: %s\n", prefix, searchHit.getRow().toString());
}
// 各行の列のハイライトされたテキストセグメントを表示します。
if (searchHit.getHighlightResultItem() != null) {
System.out.printf("%s Highlight: \n", prefix);
StringBuilder strBuilder = new StringBuilder();
for (Map.Entry<String, HighlightField> entry : searchHit.getHighlightResultItem().getHighlightFields().entrySet()) {
strBuilder.append(entry.getKey()).append(":").append("[");
strBuilder.append(StringUtils.join(",", entry.getValue().getFragments())).append("]\n");
}
System.out.printf("%s %s", prefix, strBuilder);
}
// ネスト列のハイライトされた結果。
for (SearchInnerHit searchInnerHit : searchHit.getSearchInnerHits().values()) {
System.out.printf("%s Path: %s\n", prefix, searchInnerHit.getPath());
System.out.printf("%s InnerHit: \n", prefix);
printSearchHit(searchInnerHit.getSubSearchHits(), prefix + " ");
}
System.out.println();
}
}
たとえば、Col_Nested フィールドは、Text 型の Level1_Col1_Text サブフィールドと Nested 型の Level1_Col2_Nested サブフィールドで構成されています。 Nested 型の Level1_Col2_Nested サブフィールドも Level2_Col1_Text フィールドで構成されています。
次のサンプルコードは、ネストクエリにブールクエリを追加して、Level1_Col1_Text フィールドと Level1_Col2_Nested フィールドの Level2_Col1_Text サブフィールドのクエリ文字列をハイライトする方法の例を示しています。
public static void nestedQueryWithHighlighting(SyncClient client) {
SearchRequest searchRequest = SearchRequest.newBuilder()
.tableName("<TABLE_NAME>")
.indexName("<SEARCH_INDEX_NAME>")
.returnAllColumnsFromIndex(true)
.searchQuery(SearchQuery.newBuilder()
.limit(5)
.query(QueryBuilders.nested()
.path("Col_Nested")
.scoreMode(ScoreMode.Min)
.query(QueryBuilders.bool()
.should(QueryBuilders.match("Col_Nested.Level1_Col1_Text", "hangzhou shanghai"))
.should(QueryBuilders.nested()
.path("Col_Nested.Level1_Col2_Nested")
.scoreMode(ScoreMode.Min)
.query(QueryBuilders.match("Col_Nested.Level1_Col2_Nested.Level2_Col1_Text", "hangzhou shanghai"))
.innerHits(InnerHits.newBuilder()
.highlight(Highlight.newBuilder()
.addFieldHighlightParam("Col_Nested.Level1_Col2_Nested.Level2_Col1_Text", HighlightParame
.build())
.build())))
.innerHits(InnerHits.newBuilder()
.sort(new Sort(Arrays.asList(
new ScoreSort(),
new DocSort()
)))
.highlight(Highlight.newBuilder()
.addFieldHighlightParam("Col_Nested.Level1_Col1_Text", HighlightParameter.newBuilder().build())
.build())
.build()))
.build())
.build();
SearchResponse resp = client.search(searchRequest);
// ハイライトされた結果を表示します。
printSearchHit(resp.getSearchHits(), "");
}
/**
* クエリ条件を満たすコンテンツを表示します。
* @param searchHits searchHits
* 出力が @param prefix Nested 構造を使用する場合は、プレフィックスを追加して階層情報を表示します。
*/
private static void printSearchHit(List<SearchHit> searchHits, String prefix) {
for (SearchHit searchHit : searchHits) {
if (searchHit.getScore() != null) {
System.out.printf("%s Score: %s\n", prefix, searchHit.getScore());
}
if (searchHit.getOffset() != null) {
System.out.printf("%s Offset: %s\n", prefix, searchHit.getOffset());
}
if (searchHit.getRow() != null) {
System.out.printf("%s Row: %s\n", prefix, searchHit.getRow().toString());
}
// 各行のフィールドのハイライトされたテキストセグメントを表示します。
if (searchHit.getHighlightResultItem() != null) {
System.out.printf("%s Highlight: \n", prefix);
StringBuilder strBuilder = new StringBuilder();
for (Map.Entry<String, HighlightField> entry : searchHit.getHighlightResultItem().getHighlightFields().entrySet()) {
strBuilder.append(entry.getKey()).append(":").append("[");
strBuilder.append(StringUtils.join(",", entry.getValue().getFragments())).append("]\n");
}
System.out.printf("%s %s", prefix, strBuilder);
}
// ネスト列のハイライトされた結果。
for (SearchInnerHit searchInnerHit : searchHit.getSearchInnerHits().values()) {
System.out.printf("%s Path: %s\n", prefix, searchInnerHit.getPath());
System.out.printf("%s InnerHit: \n", prefix);
printSearchHit(searchInnerHit.getSubSearchHits(), prefix + " ");
}
System.out.println();
}
}
FAQ
参考資料
検索インデックスを使用してデータをクエリする場合、次のクエリ方法を使用できます。タームクエリ、タームズクエリ、マッチオールクエリ、マッチクエリ、マッチフレーズクエリ、プレフィックスクエリ、範囲クエリ、ワイルドカードクエリ、ジオクエリ、KNNベクトル検索クエリ、ブールクエリ、ネストクエリ、存在クエリ。検索インデックスを作成した後、検索インデックスが提供するクエリ方法を使用して、ビジネス要件に基づいて多次元的にデータをクエリできます。
ソート機能とページング機能を使用して、クエリ条件を満たす行をソートまたはページングできます。詳細については、ソートとページングの実行を参照してください。
折りたたみ(重複排除)機能を使用して、特定の列に基づいて結果セットを折りたたむことができます。このようにして、指定されたタイプのデータはクエリ結果に一度だけ表示されます。詳細については、折りたたみ(重複排除)を参照してください。
テーブル内のデータを分析する場合は、Search 操作を呼び出して集計機能を使用するか、SQL クエリ機能を使用できます。たとえば、最大値、最小値、値の合計、行数をクエリできます。詳細については、集計とSQL クエリを参照してください。
行をソートする必要なく、クエリ条件を満たすすべての行を取得する場合は、ParallelScan 操作と ComputeSplits 操作を呼び出して並列スキャン機能を使用できます。詳細については、並列スキャンを参照してください。