Add support for compound queries
This commit adds support for the compound queries "bool", "boosting",
"constant_score" and "dis_max". The "function_score" query is not
supported yet.
Compound queries are simple. They act just like simple queries, except
that they are recursive, wrapping other simple/compound queries.
For example:
    esquery.Bool().
        Must(Term("user", "kimchy"), Term("author", "kimchy")).
        Filter(Term("tag", "tech"))
			
			
This commit is contained in:
		
							parent
							
								
									9ef149ec94
								
							
						
					
					
						commit
						6c8e71c188
					
				
							
								
								
									
										61
									
								
								boolean.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										61
									
								
								boolean.go
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,61 @@
 | 
			
		||||
package esquery
 | 
			
		||||
 | 
			
		||||
import "encoding/json"
 | 
			
		||||
 | 
			
		||||
/*******************************************************************************
 | 
			
		||||
 * Boolean Queries
 | 
			
		||||
 * https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-bool-query.html
 | 
			
		||||
 ******************************************************************************/
 | 
			
		||||
 | 
			
		||||
type BoolQuery struct {
 | 
			
		||||
	params boolQueryParams
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type boolQueryParams struct {
 | 
			
		||||
	Must               []json.Marshaler `json:"must,omitempty"`
 | 
			
		||||
	Filter             []json.Marshaler `json:"filter,omitempty"`
 | 
			
		||||
	MustNot            []json.Marshaler `json:"must_not,omitempty"`
 | 
			
		||||
	Should             []json.Marshaler `json:"should,omitempty"`
 | 
			
		||||
	MinimumShouldMatch int16            `json:"minimum_should_match,omitempty"`
 | 
			
		||||
	Boost              float32          `json:"boost,omitempty"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func Bool() *BoolQuery {
 | 
			
		||||
	return &BoolQuery{}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (q *BoolQuery) Must(must ...json.Marshaler) *BoolQuery {
 | 
			
		||||
	q.params.Must = append(q.params.Must, must...)
 | 
			
		||||
	return q
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (q *BoolQuery) Filter(filter ...json.Marshaler) *BoolQuery {
 | 
			
		||||
	q.params.Filter = append(q.params.Filter, filter...)
 | 
			
		||||
	return q
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (q *BoolQuery) MustNot(mustnot ...json.Marshaler) *BoolQuery {
 | 
			
		||||
	q.params.MustNot = append(q.params.MustNot, mustnot...)
 | 
			
		||||
	return q
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (q *BoolQuery) Should(should ...json.Marshaler) *BoolQuery {
 | 
			
		||||
	q.params.Should = append(q.params.Should, should...)
 | 
			
		||||
	return q
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (q *BoolQuery) MinimumShouldMatch(val int16) *BoolQuery {
 | 
			
		||||
	q.params.MinimumShouldMatch = val
 | 
			
		||||
	return q
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (q *BoolQuery) Boost(val float32) *BoolQuery {
 | 
			
		||||
	q.params.Boost = val
 | 
			
		||||
	return q
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (q BoolQuery) MarshalJSON() ([]byte, error) {
 | 
			
		||||
	return json.Marshal(map[string]boolQueryParams{
 | 
			
		||||
		"bool": q.params,
 | 
			
		||||
	})
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										31
									
								
								boolean_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								boolean_test.go
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,31 @@
 | 
			
		||||
package esquery
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"testing"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func TestBool(t *testing.T) {
 | 
			
		||||
	runTests(t, []queryTest{
 | 
			
		||||
		{
 | 
			
		||||
			"bool with only a simple must",
 | 
			
		||||
			Bool().Must(Term("tag", "tech")),
 | 
			
		||||
			"{\"bool\":{\"must\":[{\"term\":{\"tag\":{\"value\":\"tech\"}}}]}}\n",
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			"bool which must match_all and filter",
 | 
			
		||||
			Bool().Must(MatchAll()).Filter(Term("status", "active")),
 | 
			
		||||
			"{\"bool\":{\"must\":[{\"match_all\":{}}],\"filter\":[{\"term\":{\"status\":{\"value\":\"active\"}}}]}}\n",
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			"bool with a lot of stuff",
 | 
			
		||||
			Bool().
 | 
			
		||||
				Must(Term("user", "kimchy")).
 | 
			
		||||
				Filter(Term("tag", "tech")).
 | 
			
		||||
				MustNot(Range("age").Gte(10).Lte(20)).
 | 
			
		||||
				Should(Term("tag", "wow"), Term("tag", "elasticsearch")).
 | 
			
		||||
				MinimumShouldMatch(1).
 | 
			
		||||
				Boost(1.1),
 | 
			
		||||
			"{\"bool\":{\"must\":[{\"term\":{\"user\":{\"value\":\"kimchy\"}}}],\"filter\":[{\"term\":{\"tag\":{\"value\":\"tech\"}}}],\"must_not\":[{\"range\":{\"age\":{\"gte\":10,\"lte\":20}}}],\"should\":[{\"term\":{\"tag\":{\"value\":\"wow\"}}},{\"term\":{\"tag\":{\"value\":\"elasticsearch\"}}}],\"minimum_should_match\":1,\"boost\":1.1}}\n",
 | 
			
		||||
		},
 | 
			
		||||
	})
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										43
									
								
								boosting.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										43
									
								
								boosting.go
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,43 @@
 | 
			
		||||
package esquery
 | 
			
		||||
 | 
			
		||||
import "encoding/json"
 | 
			
		||||
 | 
			
		||||
/*******************************************************************************
 | 
			
		||||
 * Boosting Queries
 | 
			
		||||
 * https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-boosting-query.html
 | 
			
		||||
 ******************************************************************************/
 | 
			
		||||
 | 
			
		||||
type BoostingQuery struct {
 | 
			
		||||
	params boostingQueryParams
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type boostingQueryParams struct {
 | 
			
		||||
	Positive      json.Marshaler `json:"positive"`
 | 
			
		||||
	Negative      json.Marshaler `json:"negative"`
 | 
			
		||||
	NegativeBoost float32        `json:"negative_boost"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func Boosting() *BoostingQuery {
 | 
			
		||||
	return &BoostingQuery{}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (q *BoostingQuery) Positive(p json.Marshaler) *BoostingQuery {
 | 
			
		||||
	q.params.Positive = p
 | 
			
		||||
	return q
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (q *BoostingQuery) Negative(p json.Marshaler) *BoostingQuery {
 | 
			
		||||
	q.params.Negative = p
 | 
			
		||||
	return q
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (q *BoostingQuery) NegativeBoost(b float32) *BoostingQuery {
 | 
			
		||||
	q.params.NegativeBoost = b
 | 
			
		||||
	return q
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (q *BoostingQuery) MarshalJSON() ([]byte, error) {
 | 
			
		||||
	return json.Marshal(map[string]boostingQueryParams{
 | 
			
		||||
		"boosting": q.params,
 | 
			
		||||
	})
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										18
									
								
								boosting_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								boosting_test.go
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,18 @@
 | 
			
		||||
package esquery
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"testing"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func TestBoost(t *testing.T) {
 | 
			
		||||
	runTests(t, []queryTest{
 | 
			
		||||
		{
 | 
			
		||||
			"boosting query",
 | 
			
		||||
			Boosting().
 | 
			
		||||
				Positive(Term("text", "apple")).
 | 
			
		||||
				Negative(Term("text", "pie tart")).
 | 
			
		||||
				NegativeBoost(0.5),
 | 
			
		||||
			"{\"boosting\":{\"positive\":{\"term\":{\"text\":{\"value\":\"apple\"}}},\"negative\":{\"term\":{\"text\":{\"value\":\"pie tart\"}}},\"negative_boost\":0.5}}\n",
 | 
			
		||||
		},
 | 
			
		||||
	})
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										29
									
								
								constant_score.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								constant_score.go
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,29 @@
 | 
			
		||||
package esquery
 | 
			
		||||
 | 
			
		||||
import "encoding/json"
 | 
			
		||||
 | 
			
		||||
type ConstantScoreQuery struct {
 | 
			
		||||
	params constantScoreParams
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type constantScoreParams struct {
 | 
			
		||||
	Filter json.Marshaler `json:"filter"`
 | 
			
		||||
	Boost  float32        `json:"boost,omitempty"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func ConstantScore(filter json.Marshaler) *ConstantScoreQuery {
 | 
			
		||||
	return &ConstantScoreQuery{
 | 
			
		||||
		params: constantScoreParams{Filter: filter},
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (q *ConstantScoreQuery) Boost(b float32) *ConstantScoreQuery {
 | 
			
		||||
	q.params.Boost = b
 | 
			
		||||
	return q
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (q ConstantScoreQuery) MarshalJSON() ([]byte, error) {
 | 
			
		||||
	return json.Marshal(map[string]constantScoreParams{
 | 
			
		||||
		"constant_score": q.params,
 | 
			
		||||
	})
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										20
									
								
								constant_score_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								constant_score_test.go
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,20 @@
 | 
			
		||||
package esquery
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"testing"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func TestConstantScore(t *testing.T) {
 | 
			
		||||
	runTests(t, []queryTest{
 | 
			
		||||
		{
 | 
			
		||||
			"constant_score query without boost",
 | 
			
		||||
			ConstantScore(Term("user", "kimchy")),
 | 
			
		||||
			"{\"constant_score\":{\"filter\":{\"term\":{\"user\":{\"value\":\"kimchy\"}}}}}\n",
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			"constant_score query with boost",
 | 
			
		||||
			ConstantScore(Term("user", "kimchy")).Boost(2.2),
 | 
			
		||||
			"{\"constant_score\":{\"filter\":{\"term\":{\"user\":{\"value\":\"kimchy\"}}},\"boost\":2.2}}\n",
 | 
			
		||||
		},
 | 
			
		||||
	})
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										31
									
								
								dis_max.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								dis_max.go
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,31 @@
 | 
			
		||||
package esquery
 | 
			
		||||
 | 
			
		||||
import "encoding/json"
 | 
			
		||||
 | 
			
		||||
type DisMaxQuery struct {
 | 
			
		||||
	params disMaxParams
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type disMaxParams struct {
 | 
			
		||||
	Queries    []json.Marshaler `json:"queries"`
 | 
			
		||||
	TieBreaker float32          `json:"tie_breaker,omitempty"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func DisMax(queries ...json.Marshaler) *DisMaxQuery {
 | 
			
		||||
	return &DisMaxQuery{
 | 
			
		||||
		params: disMaxParams{
 | 
			
		||||
			Queries: queries,
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (q *DisMaxQuery) TieBreaker(b float32) *DisMaxQuery {
 | 
			
		||||
	q.params.TieBreaker = b
 | 
			
		||||
	return q
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (q DisMaxQuery) MarshalJSON() ([]byte, error) {
 | 
			
		||||
	return json.Marshal(map[string]disMaxParams{
 | 
			
		||||
		"dis_max": q.params,
 | 
			
		||||
	})
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										15
									
								
								dis_max_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								dis_max_test.go
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,15 @@
 | 
			
		||||
package esquery
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"testing"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func TestDisMax(t *testing.T) {
 | 
			
		||||
	runTests(t, []queryTest{
 | 
			
		||||
		{
 | 
			
		||||
			"dis_max",
 | 
			
		||||
			DisMax(Term("title", "Quick pets"), Term("body", "Quick pets")).TieBreaker(0.7),
 | 
			
		||||
			"{\"dis_max\":{\"queries\":[{\"term\":{\"title\":{\"value\":\"Quick pets\"}}},{\"term\":{\"body\":{\"value\":\"Quick pets\"}}}],\"tie_breaker\":0.7}}\n",
 | 
			
		||||
		},
 | 
			
		||||
	})
 | 
			
		||||
}
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user