Tablestore SDKを使用して、単一レベルおよび複数レベルのネストされたフィールドのデータをクエリできます。ネストクエリを実行する際に、ハイライト機能を使用して、クエリ結果のクエリ文字列をハイライト表示できます。詳細については、ハイライトを参照してください。
単一レベルのネストされたフィールドのクエリ
次のサンプルコードは、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());
}
ネストクエリとブールクエリを組み合わせる
クエリ要件
この例では、データテーブルは、Stringタイプのcol_string列とStringタイプのcol_nested列で構成されています。col_nested列には、JSON形式のデータが格納されます。次の表は、データテーブルのサンプル行を示しています。
説明 デモをより理解しやすくするために、各行にシリアル番号が追加されています。
シリアル番号 | col_string | col_nested |
1 | a | [{"col_keyword": "tablestore"},{"col_keyword": "searchindex","col_long": 1}] |
2 | b | [{"col_keyword": "tablestore","col_long": 1}] |
3 | c | [{"col_keyword": "searchindex"},{"col_long": 1}] |
たとえば、col_nested列に対して次のクエリ要件があるとします。
同じ子行が複数のクエリ条件を満たす
たとえば、col_keyword列の値が「tablestore」で、col_long列の値が空でない行をクエリするとします。col_keyword列とcol_long列は、col_nested列の同じ子行に属しています。
異なる子行が複数のクエリ条件を満たす
たとえば、col_keyword列の値が「tablestore」で、col_long列の値が空でない行をクエリするとします。col_keyword列とcol_long列は、col_nested列の同じ子行または異なる子行に属しています。
上記の要件を満たす行をクエリするには、次の手順を実行します。
データテーブルの検索インデックスを作成し、検索インデックスのcol_nested列のタイプをNestedに設定します。
col_nested列は、Keywordタイプのcol_keywordサブフィールドとLongタイプのcol_longサブフィールドで構成されます。
クエリ要件に基づいて適切なクエリメソッドを選択します。
次のサンプルコードは、クエリ要件に基づいてデータをクエリする方法の例を示しています。クエリ要件に基づいて、対応するサンプルコードを参照してください。
同じ子行が複数のクエリ条件を満たす
次のサンプルコードは、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();
}
}