public void testNestedSortWithMultiLevelFiltering()

in server/src/internalClusterTest/java/org/opensearch/search/nested/SimpleNestedIT.java [712:952]


    public void testNestedSortWithMultiLevelFiltering() throws Exception {
        assertAcked(
            prepareCreate("test").addMapping(
                "type1",
                "{\n"
                    + "  \"type1\": {\n"
                    + "    \"properties\": {\n"
                    + "      \"acl\": {\n"
                    + "        \"type\": \"nested\",\n"
                    + "        \"properties\": {\n"
                    + "          \"access_id\": {\"type\": \"keyword\"},\n"
                    + "          \"operation\": {\n"
                    + "            \"type\": \"nested\",\n"
                    + "            \"properties\": {\n"
                    + "              \"name\": {\"type\": \"keyword\"},\n"
                    + "              \"user\": {\n"
                    + "                \"type\": \"nested\",\n"
                    + "                \"properties\": {\n"
                    + "                  \"username\": {\"type\": \"keyword\"},\n"
                    + "                  \"id\": {\"type\": \"integer\"}\n"
                    + "                }\n"
                    + "              }\n"
                    + "            }\n"
                    + "          }\n"
                    + "        }\n"
                    + "      }\n"
                    + "    }\n"
                    + "  }\n"
                    + "}",
                XContentType.JSON
            )
        );
        ensureGreen();

        client().prepareIndex("test", "type1", "1")
            .setSource(
                "{\n"
                    + "  \"acl\": [\n"
                    + "    {\n"
                    + "      \"access_id\": 1,\n"
                    + "      \"operation\": [\n"
                    + "        {\n"
                    + "          \"name\": \"read\",\n"
                    + "          \"user\": [\n"
                    + "            {\"username\": \"grault\", \"id\": 1},\n"
                    + "            {\"username\": \"quxx\", \"id\": 2},\n"
                    + "            {\"username\": \"bar\", \"id\": 3}\n"
                    + "          ]\n"
                    + "        },\n"
                    + "        {\n"
                    + "          \"name\": \"write\",\n"
                    + "          \"user\": [\n"
                    + "            {\"username\": \"quxx\", \"id\": 2},\n"
                    + "            {\"username\": \"bar\", \"id\": 3}\n"
                    + "          ]\n"
                    + "        }\n"
                    + "      ]\n"
                    + "    },\n"
                    + "    {\n"
                    + "      \"access_id\": 2,\n"
                    + "      \"operation\": [\n"
                    + "        {\n"
                    + "          \"name\": \"read\",\n"
                    + "          \"user\": [\n"
                    + "            {\"username\": \"baz\", \"id\": 4},\n"
                    + "            {\"username\": \"quxx\", \"id\": 2}\n"
                    + "          ]\n"
                    + "        },\n"
                    + "        {\n"
                    + "          \"name\": \"write\",\n"
                    + "          \"user\": [\n"
                    + "            {\"username\": \"quxx\", \"id\": 2}\n"
                    + "          ]\n"
                    + "        },\n"
                    + "        {\n"
                    + "          \"name\": \"execute\",\n"
                    + "          \"user\": [\n"
                    + "            {\"username\": \"quxx\", \"id\": 2}\n"
                    + "          ]\n"
                    + "        }\n"
                    + "      ]\n"
                    + "    }\n"
                    + "  ]\n"
                    + "}",
                XContentType.JSON
            )
            .get();

        client().prepareIndex("test", "type1", "2")
            .setSource(
                "{\n"
                    + "  \"acl\": [\n"
                    + "    {\n"
                    + "      \"access_id\": 1,\n"
                    + "      \"operation\": [\n"
                    + "        {\n"
                    + "          \"name\": \"read\",\n"
                    + "          \"user\": [\n"
                    + "            {\"username\": \"grault\", \"id\": 1},\n"
                    + "            {\"username\": \"foo\", \"id\": 5}\n"
                    + "          ]\n"
                    + "        },\n"
                    + "        {\n"
                    + "          \"name\": \"execute\",\n"
                    + "          \"user\": [\n"
                    + "            {\"username\": \"foo\", \"id\": 5}\n"
                    + "          ]\n"
                    + "        }\n"
                    + "      ]\n"
                    + "    },\n"
                    + "    {\n"
                    + "      \"access_id\": 3,\n"
                    + "      \"operation\": [\n"
                    + "        {\n"
                    + "          \"name\": \"read\",\n"
                    + "          \"user\": [\n"
                    + "            {\"username\": \"grault\", \"id\": 1}\n"
                    + "          ]\n"
                    + "        },\n"
                    + "        {\n"
                    + "          \"name\": \"write\",\n"
                    + "          \"user\": [\n"
                    + "            {\"username\": \"grault\", \"id\": 1}\n"
                    + "          ]\n"
                    + "        },\n"
                    + "        {\n"
                    + "          \"name\": \"execute\",\n"
                    + "          \"user\": [\n"
                    + "            {\"username\": \"grault\", \"id\": 1}\n"
                    + "          ]\n"
                    + "        }\n"
                    + "      ]\n"
                    + "    }\n"
                    + "  ]\n"
                    + "}",
                XContentType.JSON
            )
            .get();
        refresh();

        // access id = 1, read, max value, asc, should use grault and quxx
        SearchResponse searchResponse = client().prepareSearch()
            .setQuery(matchAllQuery())
            .addSort(
                SortBuilders.fieldSort("acl.operation.user.username")
                    .setNestedSort(
                        new NestedSortBuilder("acl").setFilter(QueryBuilders.termQuery("acl.access_id", "1"))
                            .setNestedSort(
                                new NestedSortBuilder("acl.operation").setFilter(QueryBuilders.termQuery("acl.operation.name", "read"))
                                    .setNestedSort(new NestedSortBuilder("acl.operation.user"))
                            )
                    )
                    .sortMode(SortMode.MAX)
                    .order(SortOrder.ASC)
            )
            .get();

        assertHitCount(searchResponse, 2);
        assertThat(searchResponse.getHits().getHits().length, equalTo(2));
        assertThat(searchResponse.getHits().getHits()[0].getId(), equalTo("2"));
        assertThat(searchResponse.getHits().getHits()[0].getSortValues()[0].toString(), equalTo("grault"));
        assertThat(searchResponse.getHits().getHits()[1].getId(), equalTo("1"));
        assertThat(searchResponse.getHits().getHits()[1].getSortValues()[0].toString(), equalTo("quxx"));

        // access id = 1, read, min value, asc, should now use bar and foo
        searchResponse = client().prepareSearch()
            .setQuery(matchAllQuery())
            .addSort(
                SortBuilders.fieldSort("acl.operation.user.username")
                    .setNestedSort(
                        new NestedSortBuilder("acl").setFilter(QueryBuilders.termQuery("acl.access_id", "1"))
                            .setNestedSort(
                                new NestedSortBuilder("acl.operation").setFilter(QueryBuilders.termQuery("acl.operation.name", "read"))
                                    .setNestedSort(new NestedSortBuilder("acl.operation.user"))
                            )
                    )
                    .sortMode(SortMode.MIN)
                    .order(SortOrder.ASC)
            )
            .get();

        assertHitCount(searchResponse, 2);
        assertThat(searchResponse.getHits().getHits().length, equalTo(2));
        assertThat(searchResponse.getHits().getHits()[0].getId(), equalTo("1"));
        assertThat(searchResponse.getHits().getHits()[0].getSortValues()[0].toString(), equalTo("bar"));
        assertThat(searchResponse.getHits().getHits()[1].getId(), equalTo("2"));
        assertThat(searchResponse.getHits().getHits()[1].getSortValues()[0].toString(), equalTo("foo"));

        // execute, by grault or foo, by user id, sort missing first
        searchResponse = client().prepareSearch()
            .setQuery(matchAllQuery())
            .addSort(
                SortBuilders.fieldSort("acl.operation.user.id")
                    .setNestedSort(
                        new NestedSortBuilder("acl").setNestedSort(
                            new NestedSortBuilder("acl.operation").setFilter(QueryBuilders.termQuery("acl.operation.name", "execute"))
                                .setNestedSort(
                                    new NestedSortBuilder("acl.operation.user").setFilter(
                                        QueryBuilders.termsQuery("acl.operation.user.username", "grault", "foo")
                                    )
                                )
                        )
                    )
                    .missing("_first")
                    .sortMode(SortMode.MIN)
                    .order(SortOrder.DESC)
            )
            .get();

        assertHitCount(searchResponse, 2);
        assertThat(searchResponse.getHits().getHits().length, equalTo(2));
        assertThat(searchResponse.getHits().getHits()[0].getId(), equalTo("1")); // missing first
        assertThat(searchResponse.getHits().getHits()[1].getId(), equalTo("2"));
        assertThat(searchResponse.getHits().getHits()[1].getSortValues()[0].toString(), equalTo("1"));

        // execute, by grault or foo, by username, sort missing last (default)
        searchResponse = client().prepareSearch()
            .setQuery(matchAllQuery())
            .addSort(
                SortBuilders.fieldSort("acl.operation.user.username")
                    .setNestedSort(
                        new NestedSortBuilder("acl").setNestedSort(
                            new NestedSortBuilder("acl.operation").setFilter(QueryBuilders.termQuery("acl.operation.name", "execute"))
                                .setNestedSort(
                                    new NestedSortBuilder("acl.operation.user").setFilter(
                                        QueryBuilders.termsQuery("acl.operation.user.username", "grault", "foo")
                                    )
                                )
                        )
                    )
                    .sortMode(SortMode.MIN)
                    .order(SortOrder.DESC)
            )
            .get();

        assertHitCount(searchResponse, 2);
        assertThat(searchResponse.getHits().getHits().length, equalTo(2));
        assertThat(searchResponse.getHits().getHits()[0].getId(), equalTo("2"));
        assertThat(searchResponse.getHits().getHits()[0].getSortValues()[0].toString(), equalTo("foo"));
        assertThat(searchResponse.getHits().getHits()[1].getId(), equalTo("1")); // missing last
    }