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

fixes invalid query nesting generation #163

Merged
merged 1 commit into from
Jan 30, 2018
Merged

Conversation

ferronrsmith
Copy link
Collaborator

bodybuilder now generates valid nested query

fixes #142
fixes #162

@johannes-scharlach
Copy link
Collaborator

I think I've tried to address this in #144 but I'd also extended the tests and they broke after applying my changes.

Could you add the tests I've created in 55d6aef and see if they pass? (The changes are from August, so I don't remember everything exactly...)

@ferronrsmith
Copy link
Collaborator Author

ferronrsmith commented Jan 29, 2018

Nope doesn't seem to work.

/// this works
bodyBuilder().query('has_parent', 'parent_type', 'blog', (q) => {
    return q.query('term', 'tag', 'something')

bodybuilder now generates valid nested queries

fixes #142
fixes #162
@richardwhatever
Copy link

hi guys, this still is a problem in current release 2.2.7

@ferronrsmith
Copy link
Collaborator Author

ferronrsmith commented Mar 7, 2018

@richardwhatever Can you create an issue with the problem ? That statement doesn't really help us diagnose the issue

@richardwhatever
Copy link

richardwhatever commented Mar 7, 2018

Sure, when i try and run code like this:

 bb.aggregation('filter', fieldName, aggName, (a) => {
      return a.filter('nested', {path: 'skus'}, (n) => {
		return n.query('terms', { 'material': 'wood' })
		})
        .aggregation('terms', fieldName, aggName)
    })

BodyBuilder errors saying "TypeError: n.query is not a function" but I can't add a query under a filter. Elasticsearch needs it to be a query there, not filter.

@ferronrsmith
Copy link
Collaborator Author

Create a separate issue for this

@ferronrsmith
Copy link
Collaborator Author

i.e The problem also lies with your query. You are nesting a query inside a filter ...

Have you tried ?

 bb.aggregation('filter', fieldName, aggName, (a) => {
      return a.filter('nested', {path: 'skus'}, (n) => {
		return n.filter('terms', { 'material': 'wood' })
		})
        .aggregation('terms', fieldName, aggName)
    })

@ferronrsmith ferronrsmith deleted the bug/query_nesting branch March 12, 2018 05:37
@eliath
Copy link

eliath commented Apr 27, 2018

I can't seem to get nested queries to work

For example, I want:

  • Match "george" in the name field OR the email field.
  • Filter for gender=male.
searchQuery = 'george'
filterKey = 'gender'
filterValue = 'male'

bodybuilder()
  .query('bool', b => b
    .orQuery('match', 'name', searchQuery)
    .orQuery('match', 'email', searchQuery))
  .filter('term', filterKey, filterValue)
  .build()

This results in:

{
  query: {
    bool: {
      filter: {
        term: { gender: "male" }
      },
      query: {    // <-- I want this to be "must"
        bool: {
          should: [
            { match: { name: "george" } },
            { match: { email: "george" } }
          ]
        }
      }
    }
  }
}

and the corresponding Elasticsearch error:

Error: [parsing_exception] [bool] query does not support [query]

What is the correct syntax to nest queries as described above?

@johannes-scharlach
Copy link
Collaborator

johannes-scharlach commented Apr 27, 2018 via email

@ferronrsmith
Copy link
Collaborator Author

ferronrsmith commented Apr 27, 2018

@eliath not sure what version you are running, but when I run it with the latest. Use http://bodybuilder.js.org/ to test you queries against the latest build.

searchQuery = 'george'
filterKey = 'gender'
filterValue = 'male'

bodybuilder()
  .query('bool', b => b
    .orQuery('match', 'name', searchQuery)
    .orQuery('match', 'email', searchQuery))
  .filter('term', filterKey, filterValue)
  .build()

==>

{
  "query": {
    "bool": {
      "filter": {
        "term": {
          "gender": "male"
        }
      },
      "should": [
        {
          "match": {
            "name": "george"
          }
        },
        {
          "match": {
            "email": "george"
          }
        }
      ]
    }
  }
}

And if you want a must you can't use an orQuery

Should be =>

searchQuery = 'george'
filterKey = 'gender'
filterValue = 'male'

bodybuilder()
  .query('bool', b => b
    .query('match', 'name', searchQuery)
    .query('match', 'email', searchQuery))
  .filter('term', filterKey, filterValue)
  .build()

=>

{
  "query": {
    "bool": {
      "filter": {
        "term": {
          "gender": "male"
        }
      },
      "must": [
        {
          "match": {
            "name": "george"
          }
        },
        {
          "match": {
            "email": "george"
          }
        }
      ]
    }
  }
}

@eliath
Copy link

eliath commented Apr 27, 2018

Thanks for your help. I tried your suggestion, it makes sense but doesn't solve my problem because of the ElasticSearch behavior.

bodybuilder()
  .orQuery('match', 'name', 'george')
  .orQuery('match', 'email', 'george')
  .filter('term', 'gender', 'male')
  .build()

Resulting body:

{
  query: {
    bool: {
      filter: {
        term: { gender: "male" }
      },
      should: [
        { match: { name: "george" } },
        { match: { email: "george" } }
      ]
    }
  }
}

Looks good, but because there is a "filter" clause, it changes the behavior of the "bool" clause.

From ElasticSearch docs on bool queries:

should: The clause (query) should appear in the matching document. If the bool query is in a query context and has a must or filter clause then a document will match the bool query even if none of the should queries match.

So the result of using this body to search is the union of:

  • All documents filtered for gender=male
  • All documents with "george" in name or email field

What I want is the intersection of the above two criteria.

Any ideas? Otherwise I will specify the clause manually as indicated in this comment

@ferronrsmith
Copy link
Collaborator Author

ferronrsmith commented Apr 27, 2018

have u tried adding a minimum_should_match ?

bodybuilder()
  .orQuery('match', 'name', 'george')
  .orQuery('match', 'email', 'george')
  .queryMinimumShouldMatch(1)
  .filter('term', 'gender', 'male')
  .build()

this would give u the intersection of gender+name OR gender+email OR gender+name+email

@johannes-scharlach
Copy link
Collaborator

Or seeing as you don't seem to care about the scoring orFilter instead of orQuery might be right for you?

@eliath
Copy link

eliath commented Apr 27, 2018

queryMinimumShouldMatch does the trick, thanks all for the input

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

Successfully merging this pull request may close these issues.

Nested bool query with must Invalid nested bool query with more "query", but works with "filter"
4 participants