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

Cannot build valid 'nested' queries in filter context #183

Closed
cricketts opened this issue May 23, 2018 · 6 comments
Closed

Cannot build valid 'nested' queries in filter context #183

cricketts opened this issue May 23, 2018 · 6 comments

Comments

@cricketts
Copy link

From what I can tell, it's not possible to perform a nested query inside of a filter context with BodyBuilder:

bodybuilder().orFilter('nested', 'path', 'my_path', b => 
  b.query('term', 'my_path.my_field', 'my_value')
)

This doesn't work because b.query does not exist, and instead only various filter functions are available. I believe this has to do with being in the "filter context" because of the outer orFilter().

If I try to use filter, however:

bodybuilder().orFilter('nested', 'path', 'my_path', b => 
  b.filter('term', 'my_path.my_field', 'my_value')
)

This results in a 400 Bad Request from Elasticsearch because filters inside of a nested field is not supported. I am running against Elasticsearch v6.2.

If I use an orQuery at the top-level this works fine:

bodybuilder().orQuery('nested', 'path', 'my_path', b => 
  b.query('term', 'my_path.my_field', 'my_value')
)

However this doesn't work for me because I want my boolean condition to live in the filter context with my other conditions and it's cheaper to perform.

@johannes-scharlach
Copy link
Collaborator

Thanks for letting us know!

I think it's quite logical that you can't use query inside of a filter – after all it's filter context and therefore only filters are available. Let me know if I'm missing something 😃

As for the bad request with the nested .filter: That should surely not happen. I tried addressing this issue in #144, but most users got around the problem for the time being, so I didn't pursue the fix.

One workaround in the mean time (and I realise this is not optimal) would be:

bodybuilder().orFilter('nested', {
  path: 'my_path',
  ...bodybuilder().query('term', 'my_path.my_field', 'my_value').build()
})

and it's cheaper to perform

I've read this in a couple of issues here, but haven't seen any benchmarks. Have you tested the performance difference?

@cricketts
Copy link
Author

cricketts commented May 23, 2018

Thanks for the prompt response!

I think it's quite logical that you can't use query inside of a filter – after all it's filter context and therefore only filters are available. Let me know if I'm missing something

That's correct for most queries, but not quite true for nested documents. Nested queries are performed against the nested objects as if they were indexed as separate documents. In fact, there is no filter context for nested documents, hence the 400 Bad Request.

For example, this is a valid query, where the nested query is in the filter context of the top-level query:

GET my_index/_search
{
  "query": {
    "bool": {
      "filter": {
        "nested": {
          "path": "my_path",
          "query": {
            "term": {
              "my_path.my_field": "my_value"
            }
          }
        }
      }
    }
  }
}

One workaround in the mean time ...

This works great, thank you!

I've read this in a couple of issues here, but haven't seen any benchmarks. Have you tested the performance difference?

I have not tested this, but I run this query in context of other conditionals, so I would have to move all of my conditionals to the query context, which is not something I will do.

One of the biggest performance differences is that Elasticsearch caches frequently used filters whereas queries generate a score and are more expensive to compute.

@AncientSwordRage
Copy link

I have been trying to follow this issue (as I have a similar one) and I cannot get

bodybuilder().orFilter('nested', {
  path: 'my_path',
  ...bodybuilder().query('term', 'my_path.my_field', 'my_value').build()
})

to run in the repl at https://bodybuilder.js.org/ is that expected or is it something we can fix?

@conradoramalho
Copy link

conradoramalho commented Jun 20, 2018

@AncientSwordRage, you must enter .build() at the end

bodybuilder().orFilter('nested', {
  path: 'my_path',
  ...bodybuilder().query('term', 'my_path.my_field', 'my_value').build()
}).build()

@conradoramalho
Copy link

conradoramalho commented Jun 20, 2018

I solved the problem using:

bodybuilder()
        .filter('term', 'agency_id', '115') 
        .filter('nested', {
          path: 'brokers',
          ...bodybuilder()
            .query('term', 'brokers.broker_customer_service_type_id', 2)
            .query('term', 'brokers.broker_id', 167415)
            .build()
        }) 
  	.filter('range', 'profiles.beds', {gte: 2})   
  	.orFilter('term', 'profiles.rent', true)   		 
  	.build()

@quinnlangille
Copy link
Contributor

quinnlangille commented Jun 26, 2018

@johannes-scharlach's solve worked for me. If there's no plans on adding nested filter functionality in the near future, this should probably be documented as a workaround :~)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants