Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Throw if two inner_hits have the same name #37645

Merged
merged 8 commits into from
Feb 1, 2019
Merged

Conversation

dvehar
Copy link
Contributor

@dvehar dvehar commented Jan 21, 2019

Fixes #37584

@jimczi jimczi added >bug :Search/Search Search-related issues that do not fall into other categories v7.0.0 v6.7.0 labels Jan 21, 2019
@elasticmachine
Copy link
Collaborator

Pinging @elastic/es-search

Copy link
Contributor

@jimczi jimczi left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @dvehar , the change looks great.
I left some comments regarding the unit tests, we also need an integration test that check that setting two inner hits with the same name throws an exception during the execution of the query. Can you add one in NestedIT for instance ?


try {
queryBuilder.extractInnerHitBuilders(Collections.singletonMap("some_name", null));
fail("Expected an IllegalArgumentException to be thrown");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you use IllegalArgumentException e = expectThrows(IllegalArgumentException.class, () -> queryBuilder.extractInnerHitBuilders(Collections.singletonMap("some_name", null)); instead ?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you change the test to use the static function InnerHitContextBuilder#extractInnerHits to retrieve the builders ? It's the function we use to build the inner hits map.


try {
queryBuilder.extractInnerHitBuilders(Collections.singletonMap("some_name", null));
fail("Expected an IllegalArgumentException to be thrown");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same here


try {
queryBuilder.extractInnerHitBuilders(Collections.singletonMap("some_name", null));
fail("Expected an IllegalArgumentException to be thrown");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

and here ;)

@dvehar
Copy link
Contributor Author

dvehar commented Jan 22, 2019

I'll work on the integration test soon

@dvehar
Copy link
Contributor Author

dvehar commented Jan 24, 2019

@jimczi Could you provide some guidance as to what my test case should look like?

public void testExtractInnerHitBuildersWithDuplicate() throws Exception {
        assertAcked(
            prepareCreate("idxduplicatehitnames")
                .setSettings(Settings.builder().put(SETTING_NUMBER_OF_SHARDS, 1).put(SETTING_NUMBER_OF_REPLICAS, 0))
                .addMapping("product", "categories", "type=keyword", "name", "type=text", "property", "type=nested")
        );
        ensureGreen("idxduplicatehitnames");

        client().prepareIndex("idxduplicatehitnames", "product", "1").setSource(jsonBuilder().startObject()
            .field("name", "product1")
            .array("categories", "1", "2", "3", "4")
            .startArray("property")
            .startObject().field("id", 1).endObject()
            .startObject().field("id", 2).endObject()
            .startObject().field("id", 3).endObject()
            .endArray()
            .endObject()).get();
        client().prepareIndex("idxduplicatehitnames", "product", "2").setSource(jsonBuilder().startObject()
            .field("name", "product2")
            .array("categories", "1", "2")
            .startArray("property")
            .startObject().field("id", 1).endObject()
            .startObject().field("id", 5).endObject()
            .startObject().field("id", 4).endObject()
            .endArray()
            .endObject()).get();
        refresh();

//        SearchResponse response = client().prepareSearch("idxduplicatehitnames").setTypes("product")
//            .addAggregation(terms("category").field("categories").subAggregation(
//                nested("property", "property").subAggregation(
//                    terms("property_id").field("property.id")
//                )
//                .innerHit(new InnerHitBuilder())
//            ))
//            .innerHit(new InnerHitBuilder())
//            .get();

//        SearchResponse response = (SearchResponse)client().prepareSearch(new String[]{"test"})
//            .setQuery(boolQuery()
//                .must(matchQuery("key", "value"))
//                .should(
//                    nestedQuery("nested_type", matchAllQuery(), ScoreMode.None)
//                        .innerHit(new InnerHitBuilder()), ScoreMode.None)
//                .innerHit(new InnerHitBuilder()))
//            .get();

//
//        SearchResponse response = client().prepareSearch("idxduplicatehitnames").addAggregation(nested("to_method", "methods")
//            .subAggregation(filter("num_string_params1",
//                nestedQuery("methods.parameters", termQuery("methods.parameters.type", "String"), ScoreMode.None).innerHit(new InnerHitBuilder("n1"))))
//                .subAggregation(filter("num_string_params2",
//                    nestedQuery("methods.parameters", termQuery("methods.parameters.type", "String"), ScoreMode.None).innerHit(new InnerHitBuilder("n2"))))
//                .subAggregation(filter("num_string_params3",
//                    nestedQuery("methods.parameters", termQuery("methods.parameters.type", "String"), ScoreMode.None).innerHit(new InnerHitBuilder("n1"))))
//        ).get();

//        SearchResponse response = client()
//            .prepareSearch("idxduplicatehitnames")
//            .setTypes("product")
//            .addAggregation(
//                terms("category")
//                    .field("categories")
//                    .subAggregation(filter("n1", nestedQuery("property", termQuery("property.id", 1D), ScoreMode.None).innerHit(new InnerHitBuilder("ih1"))))
//                    .subAggregation(filter("n2", nestedQuery("property", termQuery("property.id", 2D), ScoreMode.None).innerHit(new InnerHitBuilder("ih2"))))
//                    .subAggregation(filter("n3", nestedQuery("property", termQuery("property.id", 5D), ScoreMode.None).innerHit(new InnerHitBuilder("ih1"))))
//            )
//            .get();


        SearchResponse response = client()
            .prepareSearch("idxduplicatehitnames")
            .setTypes("product")
            .addAggregation(
                terms("category")
                    .field("categories")
                    .subAggregation(filter("n1", nestedQuery("property", termQuery("property.id", 1D), ScoreMode.None).innerHit(new InnerHitBuilder("ih1"))))
                    .subAggregation(filter("n2", nestedQuery("property", termQuery("property.id", 2D), ScoreMode.None).innerHit(new InnerHitBuilder("ih2"))))
                    .subAggregation(filter("n3", nestedQuery("property", termQuery("property.id", 5D), ScoreMode.None).innerHit(new InnerHitBuilder("ih1")).innerHit(new InnerHitBuilder("ih1"))))
            )
            .addAggregation(
                terms("category2")
                    .field("categories")
                    .subAggregation(filter("n4", nestedQuery("property", termQuery("property.id", 1D), ScoreMode.None).innerHit(new InnerHitBuilder("ih1"))))
                    .subAggregation(filter("n5", nestedQuery("property", termQuery("property.id", 2D), ScoreMode.None).innerHit(new InnerHitBuilder("ih2"))))
                    .subAggregation(filter("n6", nestedQuery("property", termQuery("property.id", 5D), ScoreMode.None).innerHit(new InnerHitBuilder("ih1")).innerHit(new InnerHitBuilder("ih1"))))
            )
            .get();

        assertNoFailures(response);
//        assertHitCount(response, 2);
    }

I've tried a few things but can't seem to get NestedQueryBuilder::extractInnerHitBuilders to be called. I'll keep working on it meanwhile.

@jimczi
Copy link
Contributor

jimczi commented Jan 24, 2019

I've tried a few things but can't seem to get NestedQueryBuilder::extractInnerHitBuilders to be called.

I tested locally and the following query failed with the check that you added in this pr:

SearchResponse response = client().prepareSearch("idxduplicatehitnames")
          .setQuery(boolQuery()
              .must(matchAllQuery())
              .should(nestedQuery("nested_type", matchAllQuery(), ScoreMode.None).innerHit(new InnerHitBuilder()))
              .should(nestedQuery("nested_type", matchAllQuery(), ScoreMode.None).innerHit(new InnerHitBuilder()))
          ).get();

You should not test aggregations, that's a different issue but we should not allow inner hits in the filter aggregations. They are not supported there so extractInnerHitBuilders is never called.

@dvehar dvehar force-pushed the fix-37584 branch 5 times, most recently from aebb18b to b205f9d Compare January 25, 2019 07:26
@dvehar
Copy link
Contributor Author

dvehar commented Jan 25, 2019

@jimczi looks good?

Copy link
Contributor

@jimczi jimczi left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for updating @dvehar . I left more comments.

@@ -460,6 +460,10 @@ protected QueryBuilder doRewrite(QueryRewriteContext queryShardContext) throws I
@Override
protected void extractInnerHitBuilders(Map<String, InnerHitContextBuilder> innerHits) {
if (innerHitBuilder != null) {
if (innerHits.containsKey(innerHitBuilder.getName())) {
throw new IllegalArgumentException("innerHits already contains an entry for key [" + innerHitBuilder.getName() + "]");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we should use the same format for the message than the option in the request, can you change innerHits to [inner_hits] ?

@@ -285,6 +285,10 @@ protected QueryBuilder doRewrite(QueryRewriteContext queryShardContext) throws I
@Override
protected void extractInnerHitBuilders(Map<String, InnerHitContextBuilder> innerHits) {
if (innerHitBuilder != null) {
if (innerHits.containsKey(innerHitBuilder.getName())) {
throw new IllegalArgumentException("innerHits already contains an entry for key [" + innerHitBuilder.getName() + "]");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here, innerHits-> [inner_hits]

@@ -317,10 +318,14 @@ protected QueryBuilder doRewrite(QueryRewriteContext queryRewriteContext) throws
@Override
public void extractInnerHitBuilders(Map<String, InnerHitContextBuilder> innerHits) {
if (innerHitBuilder != null) {
if (innerHits.containsKey(innerHitBuilder.getName())) {
throw new IllegalArgumentException("innerHits already contains an entry for key [" + innerHitBuilder.getName() + "]");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

innerHits -> [inner_hits]

@@ -460,6 +460,10 @@ protected QueryBuilder doRewrite(QueryRewriteContext queryShardContext) throws I
@Override
protected void extractInnerHitBuilders(Map<String, InnerHitContextBuilder> innerHits) {
if (innerHitBuilder != null) {
if (innerHits.containsKey(innerHitBuilder.getName())) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If innerHitBuilder.getName() is null we use the type as the name (see below). Can you build the name first and check in the inner hits map with the inferred one ?:

String name = innerHitBuilder.getName() != null ? innerHitBuilder.getName() : type;
if (innerHits.containsKey(name)) {
...

@@ -285,6 +285,10 @@ protected QueryBuilder doRewrite(QueryRewriteContext queryShardContext) throws I
@Override
protected void extractInnerHitBuilders(Map<String, InnerHitContextBuilder> innerHits) {
if (innerHitBuilder != null) {
if (innerHits.containsKey(innerHitBuilder.getName())) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See above, we should check with the inferred name as well if innerHitBuilder.getName is null.

@@ -317,10 +318,14 @@ protected QueryBuilder doRewrite(QueryRewriteContext queryRewriteContext) throws
@Override
public void extractInnerHitBuilders(Map<String, InnerHitContextBuilder> innerHits) {
if (innerHitBuilder != null) {
if (innerHits.containsKey(innerHitBuilder.getName())) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

here the path is used if the name is null, can you infer the name first and then check inside the map ?

.should(nestedQuery("property", termQuery("property.id", 1D), ScoreMode.None).innerHit(new InnerHitBuilder()))
.should(nestedQuery("property", termQuery("property.id", 1D), ScoreMode.None).innerHit(new InnerHitBuilder()))
).get();
assertNoFailures(response);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This test should fail, we use the path of the nested field as the name when it is not provided so we should also detect the duplication here.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah ok. When you posted the example here I was thinking it should not fail. I'll fix this up.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ah ok, sorry it was not clear

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no worries, I think it was just my limited understanding of things.

@jimczi
Copy link
Contributor

jimczi commented Jan 28, 2019

@elasticmachine test this please

@jimczi
Copy link
Contributor

jimczi commented Jan 28, 2019

@elasticmachine test this please

Copy link
Contributor

@jimczi jimczi left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @dvehar , the changes look good to me. The tests are failing on unrelated issues so can you merge master in your branch (a simple merge) to make sure that we run the tests with the latest fixes ?

@dvehar
Copy link
Contributor Author

dvehar commented Jan 28, 2019

@jimczi done

@jimczi
Copy link
Contributor

jimczi commented Jan 28, 2019

@elasticmachine test this please

@dvehar
Copy link
Contributor Author

dvehar commented Jan 28, 2019

@jimczi
Some builds are failing on org.elasticsearch.upgrades.FullClusterRestartIT.testRecovery(FullClusterRestartIT.java:842) because of java.lang.AssertionError: expected version to be one of [8.0.0,7.6.0] but was p 0 testrecovery 7.7.0. I can look into it more later. Let me know if you are aware of the issue

@javanna
Copy link
Member

javanna commented Jan 29, 2019

hi @dvehar that last test that was failing is now addressed. could you merge master in so we can re-run tests and hopefully have a green build? ;)

@dvehar
Copy link
Contributor Author

dvehar commented Jan 29, 2019

@javanna done

@jimczi
Copy link
Contributor

jimczi commented Jan 30, 2019

@elasticmachine test this please

@javanna
Copy link
Member

javanna commented Jan 30, 2019

retest this please

@jimczi
Copy link
Contributor

jimczi commented Jan 31, 2019

retest this please

@jimczi
Copy link
Contributor

jimczi commented Feb 1, 2019

retest this please

Copy link
Contributor

@jimczi jimczi left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @dvehar , CI is finally green. Thanks for iterating and sorry for the unrelated build failures ;).

@jimczi jimczi merged commit c1c4aba into elastic:master Feb 1, 2019
jimczi pushed a commit to jimczi/elasticsearch that referenced this pull request Feb 1, 2019
This change throws an error if two inner_hits have the same name

Closes elastic#37584
jasontedor added a commit to jasontedor/elasticsearch that referenced this pull request Feb 1, 2019
* master:
  Replace awaitBusy with assertBusy in atLeastDocsIndexed (elastic#38190)
  Adjust SearchRequest version checks (elastic#38181)
  AwaitsFix testClientSucceedsWithVerificationDisabled (elastic#38213)
  Zen2ify RareClusterStateIT (elastic#38184)
  ML: Fix error race condition on stop _all datafeeds and close _all jobs (elastic#38113)
  AwaitsFix PUT mapping with _doc on an index that has types (elastic#38204)
  Allow built-in monitoring_user role to call GET _xpack API (elastic#38060)
  Update geo_shape docs to include unsupported features (elastic#38138)
  [ML] Remove "8" prefixes from file structure finder timestamp formats (elastic#38016)
  Disable bwc tests while backporting elastic#38104 (elastic#38182)
  Enable TLSv1.3 by default for JDKs with support (elastic#38103)
  Fix _host based require filters (elastic#38173)
  RestoreService should update primary terms when restoring shards of existing indices (elastic#38177)
  Throw if two inner_hits have the same name (elastic#37645)
@dvehar
Copy link
Contributor Author

dvehar commented Feb 1, 2019

@jimczi Thanks for helping me get it through!

@dvehar dvehar deleted the fix-37584 branch February 1, 2019 18:35
jimczi added a commit that referenced this pull request Feb 4, 2019
This change throws an error if two inner_hits have the same name

Closes #37584
jasontedor added a commit to jasontedor/elasticsearch that referenced this pull request Feb 4, 2019
…round-sync-6.x

* elastic/6.x:
  Fix testRestoreIncreasesPrimaryTerms on 6.x (elastic#38314)
  SQL: Remove exceptions from Analyzer (elastic#38260) (elastic#38287)
  SQL: Move metrics tracking inside PlanExecutor (elastic#38259) (elastic#38288)
  Backport of elastic#38311: Move TokenService to seqno powered cas
  Handle scheduler exceptions (elastic#38183)
  Mute MlMigrationFullClusterRestartIT#testMigration (elastic#38316)
  6.x Backport of elastic#38278: Move ML Optimistic Concurrency Control to Seq No
  Cleanup construction of interceptors (elastic#38296)
  Throw if two inner_hits have the same name (elastic#37645) (elastic#38194)
  AsyncTwoPhaseIndexerTests race condition fixed elastic#38195 Backport#37830
  Enable SSL in reindex with security QA tests (elastic#38293)
  Ensure ILM policies run safely on leader indices  (elastic#38140)
  Introduce ssl settings to reindex from remote (elastic#38292)
  Fix ordering problem in add or renew lease test (elastic#38281)
  Mute ReplicationTrackerRetentionLeaseTests#testAddOrRenewRetentionLease (elastic#38276)
  Fix NPE in Logfile Audit Filter (elastic#38120) (elastic#38271)
  Enable trace log in FollowerFailOverIT (elastic#38148)
  SQL: Generate relevant error message when grouping functions are not used in GROUP BY (elastic#38017)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
>bug :Search/Search Search-related issues that do not fall into other categories v6.7.0 v7.0.0-beta1
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants