0
0
Fork 0

fix handling of indexing dates which we cannot represent

closes #72
This commit is contained in:
Marty Schoch 2014-08-19 09:55:26 -04:00
parent 082a5b0b03
commit 41914181ae
3 changed files with 66 additions and 22 deletions

View File

@ -10,6 +10,7 @@ package document
import (
"fmt"
"math"
"time"
"github.com/couchbaselabs/bleve/analysis"
@ -17,9 +18,11 @@ import (
)
const DEFAULT_DATETIME_INDEXING_OPTIONS = STORE_FIELD | INDEX_FIELD
const DEFAULT_DATETIME_PRECISION_STEP uint = 4
var MinTimeRepresentable = time.Unix(0, math.MinInt64)
var MaxTimeRepresentable = time.Unix(0, math.MaxInt64)
type DateTimeField struct {
name string
arrayPositions []uint64
@ -100,17 +103,27 @@ func NewDateTimeFieldFromBytes(name string, arrayPositions []uint64, value []byt
}
}
func NewDateTimeField(name string, arrayPositions []uint64, dt time.Time) *DateTimeField {
func NewDateTimeField(name string, arrayPositions []uint64, dt time.Time) (*DateTimeField, error) {
return NewDateTimeFieldWithIndexingOptions(name, arrayPositions, dt, DEFAULT_DATETIME_INDEXING_OPTIONS)
}
func NewDateTimeFieldWithIndexingOptions(name string, arrayPositions []uint64, dt time.Time, options IndexingOptions) *DateTimeField {
dtInt64 := dt.UnixNano()
prefixCoded := numeric_util.MustNewPrefixCodedInt64(dtInt64, 0)
return &DateTimeField{
name: name,
arrayPositions: arrayPositions,
value: prefixCoded,
options: options,
func NewDateTimeFieldWithIndexingOptions(name string, arrayPositions []uint64, dt time.Time, options IndexingOptions) (*DateTimeField, error) {
if canRepresent(dt) {
dtInt64 := dt.UnixNano()
prefixCoded := numeric_util.MustNewPrefixCodedInt64(dtInt64, 0)
return &DateTimeField{
name: name,
arrayPositions: arrayPositions,
value: prefixCoded,
options: options,
}, nil
}
return nil, fmt.Errorf("cannot represent %s in this type", dt)
}
func canRepresent(dt time.Time) bool {
if dt.Before(MinTimeRepresentable) || dt.After(MaxTimeRepresentable) {
return false
}
return true
}

View File

@ -54,9 +54,9 @@ var people = []*Person{
Identifier: "a",
Name: "marty",
Age: 19,
Birthday: time.Unix(1000000000, 0),
Title: "mista",
Tags: []string{"gopher", "belieber"},
// has no birthday set to test handling of zero time
Title: "mista",
Tags: []string{"gopher", "belieber"},
},
&Person{
Identifier: "b",
@ -224,6 +224,22 @@ func TestIndex(t *testing.T) {
}
}
// test that 0 time doesn't get indexed
endDate = "2010-01-01"
dateRangeQuery = NewDateRangeQuery(nil, &endDate).SetField("birthday")
searchRequest = NewSearchRequest(dateRangeQuery)
searchResult, err = index.Search(searchRequest)
if err != nil {
t.Error(err)
}
if searchResult.Total != uint64(1) {
t.Errorf("expected 1 total hit for numeric range query, got %d", searchResult.Total)
} else {
if searchResult.Hits[0].ID != "b" {
t.Errorf("expected top hit id 'b', got '%s'", searchResult.Hits[0].ID)
}
}
// test behavior of arrays
// make sure we can successfully find by all elements in array
termQuery = NewTermQuery("gopher").SetField("tags")

View File

@ -331,8 +331,12 @@ func (im *IndexMapping) processProperty(property interface{}, path []string, ind
if dateTimeParser != nil {
parsedDateTime, err := dateTimeParser.ParseDateTime(propertyValueString)
if err != nil {
field := document.NewDateTimeFieldWithIndexingOptions(fieldName, indexes, parsedDateTime, options)
context.doc.AddField(field)
field, err := document.NewDateTimeFieldWithIndexingOptions(fieldName, indexes, parsedDateTime, options)
if err == nil {
context.doc.AddField(field)
} else {
log.Printf("could not build date %v", err)
}
}
}
}
@ -356,8 +360,12 @@ func (im *IndexMapping) processProperty(property interface{}, path []string, ind
context.doc.AddField(field)
} else {
// index as datetime
field := document.NewDateTimeField(pathString, indexes, parsedDateTime)
context.doc.AddField(field)
field, err := document.NewDateTimeField(pathString, indexes, parsedDateTime)
if err == nil {
context.doc.AddField(field)
} else {
log.Printf("could not build date %v", err)
}
}
}
}
@ -388,16 +396,23 @@ func (im *IndexMapping) processProperty(property interface{}, path []string, ind
fieldName := getFieldName(pathString, path, fieldMapping)
if *fieldMapping.Type == "datetime" {
options := fieldMapping.Options()
field := document.NewDateTimeFieldWithIndexingOptions(fieldName, indexes, property, options)
context.doc.AddField(field)
field, err := document.NewDateTimeFieldWithIndexingOptions(fieldName, indexes, property, options)
if err == nil {
context.doc.AddField(field)
} else {
log.Printf("could not build date %v", err)
}
}
}
} else {
// automatic indexing behavior
field := document.NewDateTimeField(pathString, indexes, property)
context.doc.AddField(field)
field, err := document.NewDateTimeField(pathString, indexes, property)
if err == nil {
context.doc.AddField(field)
} else {
log.Printf("could not build date %v", err)
}
}
default:
im.walkDocument(property, path, indexes, context)
}