func (f *FilterOp) Ids(ids ...interface{}) *FilterOp {
	f.IdsProp = &IdsFilter{Values: ids}
	return f
}
Ids adds a IDS op to the filter.
package elastigo
import (
	"encoding/json"
	"fmt"
	"github.com/araddon/gou"
)
var (
	_ = gou.DEBUG
)
type BoolClause string
type TermExecutionMode string
const (
	TEMDefault TermExecutionMode = ""
	TEMPlain TermExecutionMode = "plain"
	TEMField TermExecutionMode = "field_data"
	TEMBool TermExecutionMode = "bool"
	TEMAnd TermExecutionMode = "and"
	TEMOr TermExecutionMode = "or"
)
type FilterClause interface {
	String() string
}
type FilterWrap struct {
	boolClause string
	filters    []interface{}
}
func NewFilterWrap() *FilterWrap {
	return &FilterWrap{filters: make([]interface{}, 0), boolClause: "and"}
}
func (f *FilterWrap) String() string {
	return fmt.Sprintf(`fopv: %d:%v`, len(f.filters), f.filters)
}
func (f *FilterWrap) Bool(s string) {
	f.boolClause = s
}
func (f *FilterWrap) addFilters(fl []interface{}) {
	if len(fl) > 1 {
		fc := fl[0]
		switch fc.(type) {
		case BoolClause, string:
			f.boolClause = fc.(string)
			fl = fl[1:]
		}
	}
	f.filters = append(f.filters, fl...)
}
func (f *FilterWrap) MarshalJSON() ([]byte, error) {
	var root interface{}
	if len(f.filters) > 1 {
		root = map[string]interface{}{f.boolClause: f.filters}
	} else if len(f.filters) == 1 {
		root = f.filters[0]
	}
	return json.Marshal(root)
}
func Filter() *FilterOp {
	return &FilterOp{}
}
func CompoundFilter(fl ...interface{}) *FilterWrap {
	FilterVal := NewFilterWrap()
	FilterVal.addFilters(fl)
	return FilterVal
}
type FilterOp struct {
	TermsMap        map[string]interface{} `json:"terms,omitempty"`
	TermMap         map[string]interface{} `json:"term,omitempty"`
	RangeMap        map[string]RangeFilter `json:"range,omitempty"`
	ExistsProp      *propertyPathMarker    `json:"exists,omitempty"`
	MissingProp     *propertyPathMarker    `json:"missing,omitempty"`
	AndFilters      []*FilterOp            `json:"and,omitempty"`
	OrFilters       []*FilterOp            `json:"or,omitempty"`
	NotFilters      []*FilterOp            `json:"not,omitempty"`
	LimitProp       *LimitFilter           `json:"limit,omitempty"`
	TypeProp        *TypeFilter            `json:"type,omitempty"`
	IdsProp         *IdsFilter             `json:"ids,omitempty"`
	ScriptProp      *ScriptFilter          `json:"script,omitempty"`
	GeoDistMap      map[string]interface{} `json:"geo_distance,omitempty"`
	GeoDistRangeMap map[string]interface{} `json:"geo_distance_range,omitempty"`
}
type propertyPathMarker struct {
	Field string `json:"field"`
}
type LimitFilter struct {
	Value int `json:"value"`
}
type TypeFilter struct {
	Value string `json:"value"`
}
type IdsFilter struct {
	Type   []string      `json:"type,omitempty"`
	Values []interface{} `json:"values,omitempty"`
}
type ScriptFilter struct {
	Script   string                 `json:"script"`
	Params   map[string]interface{} `json:"params,omitempty"`
	IsCached bool                   `json:"_cache,omitempty"`
}
type RangeFilter struct {
	Gte      interface{} `json:"gte,omitempty"`
	Lte      interface{} `json:"lte,omitempty"`
	Gt       interface{} `json:"gt,omitempty"`
	Lt       interface{} `json:"lt,omitempty"`
	TimeZone string      `json:"time_zone,omitempty"`  
}
type GeoLocation struct {
	Latitude  float32 `json:"lat"`
	Longitude float32 `json:"lon"`
}
type GeoField struct {
	GeoLocation
	Field string
}
func (f *FilterOp) Term(field string, value interface{}) *FilterOp {
	if len(f.TermMap) == 0 {
		f.TermMap = make(map[string]interface{})
	}
	f.TermMap[field] = value
	return f
}
func (f *FilterOp) And(filters ...*FilterOp) *FilterOp {
	if len(f.AndFilters) == 0 {
		f.AndFilters = filters[:]
	} else {
		f.AndFilters = append(f.AndFilters, filters...)
	}
	return f
}
func (f *FilterOp) Or(filters ...*FilterOp) *FilterOp {
	if len(f.OrFilters) == 0 {
		f.OrFilters = filters[:]
	} else {
		f.OrFilters = append(f.OrFilters, filters...)
	}
	return f
}
func (f *FilterOp) Not(filters ...*FilterOp) *FilterOp {
	if len(f.NotFilters) == 0 {
		f.NotFilters = filters[:]
	} else {
		f.NotFilters = append(f.NotFilters, filters...)
	}
	return f
}
func (f *FilterOp) GeoDistance(distance string, fields ...GeoField) *FilterOp {
	f.GeoDistMap = make(map[string]interface{})
	f.GeoDistMap["distance"] = distance
	for _, val := range fields {
		f.GeoDistMap[val.Field] = val.GeoLocation
	}
	return f
}
func (f *FilterOp) GeoDistanceRange(from string, to string, fields ...GeoField) *FilterOp {
	f.GeoDistRangeMap = make(map[string]interface{})
	f.GeoDistRangeMap["from"] = from
	f.GeoDistRangeMap["to"] = to
	for _, val := range fields {
		f.GeoDistRangeMap[val.Field] = val.GeoLocation
	}
	return f
}
func NewGeoField(field string, latitude float32, longitude float32) GeoField {
	return GeoField{
		GeoLocation: GeoLocation{Latitude: latitude, Longitude: longitude},
		Field:       field}
}
func (f *FilterOp) Terms(field string, executionMode TermExecutionMode, values ...interface{}) *FilterOp {
	f.TermsMap = make(map[string]interface{})
	if executionMode != "" {
		f.TermsMap["execution"] = executionMode
	}
	f.TermsMap[field] = values
	return f
}
func (f *FilterOp) Range(field string, gte interface{},
	gt interface{}, lte interface{}, lt interface{}, timeZone string) *FilterOp {
	if f.RangeMap == nil {
		f.RangeMap = make(map[string]RangeFilter)
	}
	f.RangeMap[field] = RangeFilter{
		Gte:      gte,
		Gt:       gt,
		Lte:      lte,
		Lt:       lt,
		TimeZone: timeZone}
	return f
}
func (f *FilterOp) Type(fieldType string) *FilterOp {
	f.TypeProp = &TypeFilter{Value: fieldType}
	return f
}