0
0
Fork 0
This commit is contained in:
Christos Vontas 2018-03-28 15:40:51 +00:00 committed by GitHub
commit f6a2df99fd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 186 additions and 1 deletions

View File

@ -63,3 +63,7 @@ func NewBooleanFieldMapping() *mapping.FieldMapping {
func NewGeoPointFieldMapping() *mapping.FieldMapping {
return mapping.NewGeoPointFieldMapping()
}
func NewIPFieldMapping() *mapping.FieldMapping {
return mapping.NewIPFieldMapping()
}

View File

@ -76,7 +76,7 @@ func (dm *DocumentMapping) Validate(cache *registry.Cache) error {
}
}
switch field.Type {
case "text", "datetime", "number", "boolean", "geopoint":
case "text", "datetime", "number", "boolean", "geopoint", "IP":
default:
return fmt.Errorf("unknown field type: '%s'", field.Type)
}

View File

@ -15,8 +15,10 @@
package mapping
import (
"encoding/binary"
"encoding/json"
"fmt"
"net"
"time"
"github.com/blevesearch/bleve/analysis"
@ -149,6 +151,16 @@ func NewGeoPointFieldMapping() *FieldMapping {
}
}
// NewIPFieldMapping returns a default field mapping for IP points
func NewIPFieldMapping() *FieldMapping {
return &FieldMapping{
Type: "IP",
Store: true,
Index: true,
IncludeInAll: true,
}
}
// Options returns the indexing options for this field.
func (fm *FieldMapping) Options() document.IndexingOptions {
var rv document.IndexingOptions
@ -190,6 +202,31 @@ func (fm *FieldMapping) processString(propertyValueString string, pathString str
fm.processTime(parsedDateTime, pathString, path, indexes, context)
}
}
} else if fm.Type == "IP" {
ip := net.ParseIP(propertyValueString)
isIPv4 := ip.DefaultMask() != nil // Only IPv4 addresses have default masks
if ip != nil {
options := fm.Options()
fieldv4 := document.NewBooleanFieldWithIndexingOptions(fieldName+"_isIPv4", indexes, isIPv4, options)
context.doc.AddField(fieldv4)
fieldip1 := document.NewNumericFieldWithIndexingOptions(fieldName+"_IP1", indexes, float64(binary.BigEndian.Uint32(ip[0:4])), options)
context.doc.AddField(fieldip1)
fieldip2 := document.NewNumericFieldWithIndexingOptions(fieldName+"_IP2", indexes, float64(binary.BigEndian.Uint32(ip[4:8])), options)
context.doc.AddField(fieldip2)
fieldip3 := document.NewNumericFieldWithIndexingOptions(fieldName+"_IP3", indexes, float64(binary.BigEndian.Uint32(ip[8:12])), options)
context.doc.AddField(fieldip3)
fieldip4 := document.NewNumericFieldWithIndexingOptions(fieldName+"_IP4", indexes, float64(binary.BigEndian.Uint32(ip[12:16])), options)
context.doc.AddField(fieldip4)
fa := []string{fieldName + "_isIPv4", fieldName + "_IP1", fieldName + "_IP2", fieldName + "_IP3", fieldName + "_IP4"}
field := document.NewCompositeFieldWithIndexingOptions(fieldName, true, fa, nil, options)
context.doc.AddField(field)
if !fm.IncludeInAll {
context.excludedFromAll = append(context.excludedFromAll, fieldName)
}
}
}
}

View File

@ -216,3 +216,7 @@ func NewGeoBoundingBoxQuery(topLeftLon, topLeftLat, bottomRightLon, bottomRightL
func NewGeoDistanceQuery(lon, lat float64, distance string) *query.GeoDistanceQuery {
return query.NewGeoDistanceQuery(lon, lat, distance)
}
func NewIPRangeQuery(cidr string) *query.IPRangeQuery {
return query.NewIPRangeQuery(cidr)
}

126
search/query/ip_range.go Normal file
View File

@ -0,0 +1,126 @@
package query
import (
"encoding/binary"
"fmt"
"net"
"github.com/blevesearch/bleve/index"
"github.com/blevesearch/bleve/mapping"
"github.com/blevesearch/bleve/search"
)
type IPRangeQuery struct {
CIDRVal string `json:"cidr, omitempty"`
FieldVal string `json:"field,omitempty"`
BoostVal *Boost `json:"boost,omitempty"`
}
func NewIPRangeQuery(cidr string) *IPRangeQuery {
return &IPRangeQuery{
CIDRVal: cidr,
}
}
func (q *IPRangeQuery) SetBoost(b float64) {
boost := Boost(b)
q.BoostVal = &boost
}
func (q *IPRangeQuery) Boost() float64 {
return q.BoostVal.Value()
}
func (q *IPRangeQuery) SetField(f string) {
q.FieldVal = f
}
func (q *IPRangeQuery) Field() string {
return q.FieldVal
}
func (q *IPRangeQuery) Searcher(i index.IndexReader, m mapping.IndexMapping, options search.SearcherOptions) (search.Searcher, error) {
_, ipNet, err := net.ParseCIDR(q.CIDRVal)
if err != nil {
isIP := net.ParseIP(q.CIDRVal)
if isIP == nil {
return nil, err
}
if isIP.DefaultMask() != nil {
q.CIDRVal = q.CIDRVal + `/32`
} else {
q.CIDRVal = q.CIDRVal + `/128`
}
_, ipNet, err = net.ParseCIDR(q.CIDRVal)
if err != nil {
return nil, err
}
}
cq := ipRangeToConjuctionQuery(q.FieldVal, ipNet)
return cq.Searcher(i, m, options)
}
func (q *IPRangeQuery) Validate() error {
return nil
}
func ipRangeToConjuctionQuery(fielName string, ipNet *net.IPNet) *ConjunctionQuery {
bndrs := make([]struct {
min uint32
max uint32
}, 4)
isIPv4 := false
if ipNet.IP.DefaultMask() != nil {
isIPv4 = true
}
if ok4 := ipNet.IP.To4(); ok4 != nil {
bndrs[2].min = 0x0000FFFF
bndrs[2].max = 0x0000FFFF
bndrs[3].min = binary.BigEndian.Uint32(ok4)
a := make([]byte, 4)
m := ipNet.Mask
for i, b := range ok4 {
// calculate broadcast address (end of range)
a[i] = b | ^m[i]
}
bndrs[3].max = binary.BigEndian.Uint32(a)
} else {
// IPv6
for i, _ := range bndrs {
chunk := ipNet.IP[i*4 : (i+1)*4]
bndrs[i].min = binary.BigEndian.Uint32(chunk)
t := make([]byte, 4)
mask := ipNet.Mask[i*4 : (i+1)*4]
for k, b := range chunk {
t[k] = b | ^mask[k]
}
bndrs[i].max = binary.BigEndian.Uint32(t)
}
}
qs := make([]Query, 4)
for i, bs := range bndrs {
tq := newNumericRangeInclusiveQuery(bs.min, bs.max, true, true)
tq.SetField(fmt.Sprintf("%s_IP%d", fielName, i+1))
qs[i] = tq
}
cq := NewConjunctionQuery(qs)
blq := NewBoolFieldQuery(isIPv4)
blq.SetField(fielName + "_isIPv4")
cq.AddQuery(blq)
return cq
}
func newNumericRangeInclusiveQuery(min, max uint32, minInclusive, maxInclusive bool) *NumericRangeQuery {
m1 := float64(min)
m2 := float64(max)
return NewNumericRangeInclusiveQuery(&m1, &m2, &minInclusive, &maxInclusive)
}

View File

@ -273,6 +273,15 @@ func ParseQuery(input []byte) (Query, error) {
}
return &rv, nil
}
_, hasCidr := tmp["cidr"]
if hasCidr {
var rv IPRangeQuery
err := json.Unmarshal(input, &rv)
if err != nil {
return nil, err
}
return &rv, nil
}
return nil, fmt.Errorf("unknown query type")
}

View File

@ -31,6 +31,7 @@ var startDateStr = "2011-01-01T00:00:00Z"
var endDateStr = "2012-01-01T00:00:00Z"
var startDate time.Time
var endDate time.Time
var cidr = "192.168.0.1/32"
func init() {
var err error
@ -189,6 +190,10 @@ func TestParseQuery(t *testing.T) {
output: nil,
err: true,
},
{
input: []byte(`{"cidr":"` + cidr + `"}`),
output: NewIPRangeQuery(cidr),
},
}
for i, test := range tests {