帮助文档 Logo
平台使用
阿里云
百度云
移动云
智算服务
教育生态
登录 →
帮助文档 Logo
平台使用 阿里云 百度云 移动云 智算服务 教育生态
登录
  1. 首页
  2. 阿里云
  3. 表格存储
  4. 开发参考
  5. SDK参考
  6. Java SDK
  7. 多元索引
  8. 数据查询
  9. 基础查询
  10. 嵌套类型查询

嵌套类型查询

  • 基础查询
  • 发布于 2025-04-22
  • 0 次阅读
文档编辑
文档编辑

NestedQuery用于查询嵌套类型字段中子行的数据。嵌套类型不能直接查询,需要通过NestedQuery包装,NestedQuery中需要指定嵌套类型字段的路径和一个子查询,其中子查询可以是任意Query类型。

前提条件

  • 已初始化OTSClient。具体操作,请参见初始化Tablestore Client。

  • 已创建数据表并写入数据。具体操作,请参见创建数据表和写入数据。

  • 已在数据表上创建多元索引。具体操作,请参见创建多元索引。

参数

参数

说明

path

路径名,嵌套类型字段的树状路径。例如news.title表示嵌套类型的news字段中的title子列。

query

嵌套类型字段的子列上的查询,子列上的查询可以是任意Query类型。

scoreMode

当字段存在多个值时基于哪个值计算分数。

getTotalCount

是否返回匹配的总行数,默认为false,表示不返回。

返回匹配的总行数会影响查询性能。

weight

查询权重,用于全文检索场景中的score排序。查询时指定列的算分权重,值越大,结果中分数的值会越大。取值范围为正浮点数。

使用此参数不会影响返回的结果数,只会影响返回的结果中的分数。

tableName

数据表名称。

indexName

多元索引名称。

columnsToGet

是否返回所有列,包含returnAll和columns设置。

returnAll默认为false,表示不返回所有列,此时可以通过columns指定返回的列;如果未通过columns指定返回的列,则只返回主键列。

当设置returnAll为true时,表示返回所有列。

InnerHits

嵌套类型字段的子列的配置参数。包括如下配置项:

  • sort:Nested子行返回时的排序规则。

  • offset:当Nested列包含多个子行时,子行返回的起始位置。

  • limit:当Nested列包含多个子行时,返回子行的数量。默认值为3。

  • highlight:Nested子列高亮参数配置。具体参数配置说明请参见摘要与高亮。

示例

使用嵌套类型查询的示例如下:

单层级嵌套类型查询示例

以下示例用于查询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(); //构造NestedQuery的子查询。
    termQuery.setFieldName("col_nested.nested_1"); //设置列名,注意带有嵌套类型列的路径。
    termQuery.setTerm(ColumnValue.fromString("tablestore")); //设置要查询的值。
    nestedQuery.setQuery(termQuery);
    nestedQuery.setScoreMode(ScoreMode.None);
    searchQuery.setQuery(nestedQuery);
    //searchQuery.setGetTotalCount(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为嵌套类型字段,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(); //构造NestedQuery的子查询。
    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);//设置返回匹配的总行数。

    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_string(String类型)和col_nested(String类型)两列,其中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_nested列中同一子行同时满足col_keyword列值为"tablestore"并且col_long列值非空的行数据。

  • 不同子行满足多个查询条件

    例如查询col_nested列中只要不同子行能满足col_keyword值为"tablestore"和col_long值非空两个条件的行数据。

为了满足上述查询需求,您需要执行如下操作:

  1. 为数据表创建一个多元索引,并在多元索引中将col_nested列设置为嵌套类型。

    其中col_nested列包含col_keyword(Keyword类型)和col_long(Long类型)两个子字段。

  2. 结合查询需求使用合适的查询方式进行数据查询。

    • 如果要实现同一个子行满足多个查询条件的查询需求,您需要在NestedQuery下设置多个BoolQuery进行查询。

    • 如果要实现不同子行满足多个查询条件的查询需求,您需要在BoolQuery下设置多个NestedQuery进行查询。

进行数据查询的示例如下,请根据要实现的查询需求参考相应示例进行操作。

同一子行满足多个条件查询示例

以下示例用于查询col_nested列的同一子行同时满足col_nested.col_keyword为"tablestore"并且col_nested.col_long非空条件的行数据。

根据数据表的数据示例可知,只有行编号2对应的行数据满足查询条件。

public static void nestedQuery(SyncClient client) {
    // 查询条件一:要求col_nested子行的col_keyword列值为"tablestore"
    TermQuery termQuery = new TermQuery();
    termQuery.setFieldName("col_nested.col_keyword");
    termQuery.setTerm(ColumnValue.fromString("tablestore"));

    // 查询条件二:要求col_nested子行的col_long非空
    ExistsQuery existsQuery = new ExistsQuery();
    existsQuery.setFieldName("col_nested.col_long");

    // 通过BoolQuery的And条件,查询同时满足上述条件的子行
    List<Query> mustQueries = new ArrayList<>();
    mustQueries.add(termQuery);
    mustQueries.add(existsQuery);
    BoolQuery boolQuery = new BoolQuery();
    boolQuery.setMustQueries(mustQueries);

    // NestedQuery内部设置BoolQuery,要求某一子行同时满足多个查询条件
    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_nested.col_keyword为"tablestore"和col_nested.col_long非空两个条件的行数据。

根据数据表的数据示例可知,行编号1和行编号2对应的行数据均满足查询条件。

public static void nestedQuery(SyncClient client) {
        // 查询条件一:要求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);

        // 查询条件二:要求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);

        // 通过BoolQuery的And条件,查询满足上述条件的行
        List<Query> mustQueries = new ArrayList<>();
        mustQueries.add(nestedTermQuery);
        mustQueries.add(nestedExistsQuery);

        // BoolQuery内部包括多个NestedQuery,多个子行分别满足查询条件即可
        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());
    }

嵌套类型查询使用查询摘要与高亮示例

以下示例用于使用NestedQuery功能查询表中Col_Nested嵌套类型字段中Level1_Col1_Nested子列的值能够匹配hangzhou shanghai的数据,并在返回结果中对查询词进行高亮显示。

/**
 * NestedQuery查询摘要与高亮,通过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(), "");
}

/**
 * 打印searchHit内容。
 * @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中包括Level1_Col1_Text(Text类型)和Level1_Col2_Nested(Nested类型)两列,其中Level1_Col2_Nested嵌套类型字段包括Level2_Col1_Text子列。

以下示例用于通过在NestedQuery中添加BoolQuery对Col_Nested字段中的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", HighlightParameter.newBuilder().build())
                                                            .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(), "");
}

/**
 * 打印searchHit内容。
 * @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();
    }
}

常见问题

  • 使用多元索引Search接口查不到数据

  • 为什么使用多元索引翻页查询时Token失效了?

相关文档

  • 多元索引查询类型包括精确查询、多词精确查询、全匹配查询、匹配查询、短语匹配查询、前缀查询、范围查询、通配符查询、地理位置查询、向量检索、多条件组合查询、嵌套类型查询和列存在性查询,您可以选择合适的查询类型进行多维度数据查询。

    如果要对结果集进行排序或者翻页,您可以使用排序和翻页功能来实现。具体操作,请参见排序和翻页。

    如果要按照某一列对结果集做折叠,使对应类型的数据在结果展示中只出现一次,您可以使用折叠(去重)功能来实现。具体操作,请参见折叠(去重)。

  • 如果要进行数据分析,例如求最值、求和、统计行数等,您可以使用Search接口的统计聚合功能或者SQL查询来实现。具体操作,请参见统计聚合和SQL查询。

  • 如果要快速导出数据,而不关心整个结果集的顺序时,您可以使用ParallelScan接口和ComputeSplits接口实现多并发导出数据。具体操作,请参见并发导出数据。

相关文章

全匹配查询 2025-04-22 14:28

全匹配查询(MatchAllQuery)可以匹配所有行,常用于查询表中数据总行数,或者随机返回几条数据。 前提

精确查询 2025-04-22 14:28

精确查询(TermQuery)采用完整精确匹配的方式查询表中的数据,类似于字符串匹配。对于Text类型字段,只要Text类型的字段值分词后有词条可以精确匹配查询关键词即可,查询关键词不会被分词。

多词精确查询 2025-04-22 14:28

多词精确查询(TermsQuery)类似于精确查询(TermQuery),但是TermsQuery可以指定多个查询关键词,查询匹配这些词的数据。多个查询关键词中只要有一个词能精确匹配,该行数据就会被返回,等价于SQL中的In。

前缀查询 2025-04-22 14:28

前缀查询(PrefixQuery)是通过指定前缀条件查询索引中的数据。本文介绍如何通过Java SDK使用前缀查询。 前提条件

后缀查询 2025-04-22 14:28

后缀查询(SuffixQuery)是通过指定后缀条件查询索引中的数据,例如通过手机尾号后4位查询快递。 前提条件

通配符查询 2025-04-22 14:28

使用通配符查询(WildcardQuery)可以实现模糊查询,类似于数据库中的Like语法,例如查询文本中包含某个词或短句的数据。 背景信息

目录
Copyright © 2025 your company All Rights Reserved. Powered by 博智数字服务平台.
闽ICP备08105208号-1