1//  Copyright (c) 2014 Couchbase, Inc.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// 		http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15package document
16
17import (
18	"fmt"
19
20	"github.com/blevesearch/bleve/analysis"
21	"github.com/blevesearch/bleve/numeric"
22)
23
24const DefaultNumericIndexingOptions = StoreField | IndexField | DocValues
25
26const DefaultPrecisionStep uint = 4
27
28type NumericField struct {
29	name              string
30	arrayPositions    []uint64
31	options           IndexingOptions
32	value             numeric.PrefixCoded
33	numPlainTextBytes uint64
34}
35
36func (n *NumericField) Name() string {
37	return n.name
38}
39
40func (n *NumericField) ArrayPositions() []uint64 {
41	return n.arrayPositions
42}
43
44func (n *NumericField) Options() IndexingOptions {
45	return n.options
46}
47
48func (n *NumericField) Analyze() (int, analysis.TokenFrequencies) {
49	tokens := make(analysis.TokenStream, 0)
50	tokens = append(tokens, &analysis.Token{
51		Start:    0,
52		End:      len(n.value),
53		Term:     n.value,
54		Position: 1,
55		Type:     analysis.Numeric,
56	})
57
58	original, err := n.value.Int64()
59	if err == nil {
60
61		shift := DefaultPrecisionStep
62		for shift < 64 {
63			shiftEncoded, err := numeric.NewPrefixCodedInt64(original, shift)
64			if err != nil {
65				break
66			}
67			token := analysis.Token{
68				Start:    0,
69				End:      len(shiftEncoded),
70				Term:     shiftEncoded,
71				Position: 1,
72				Type:     analysis.Numeric,
73			}
74			tokens = append(tokens, &token)
75			shift += DefaultPrecisionStep
76		}
77	}
78
79	fieldLength := len(tokens)
80	tokenFreqs := analysis.TokenFrequency(tokens, n.arrayPositions, n.options.IncludeTermVectors())
81	return fieldLength, tokenFreqs
82}
83
84func (n *NumericField) Value() []byte {
85	return n.value
86}
87
88func (n *NumericField) Number() (float64, error) {
89	i64, err := n.value.Int64()
90	if err != nil {
91		return 0.0, err
92	}
93	return numeric.Int64ToFloat64(i64), nil
94}
95
96func (n *NumericField) GoString() string {
97	return fmt.Sprintf("&document.NumericField{Name:%s, Options: %s, Value: %s}", n.name, n.options, n.value)
98}
99
100func (n *NumericField) NumPlainTextBytes() uint64 {
101	return n.numPlainTextBytes
102}
103
104func NewNumericFieldFromBytes(name string, arrayPositions []uint64, value []byte) *NumericField {
105	return &NumericField{
106		name:              name,
107		arrayPositions:    arrayPositions,
108		value:             value,
109		options:           DefaultNumericIndexingOptions,
110		numPlainTextBytes: uint64(len(value)),
111	}
112}
113
114func NewNumericField(name string, arrayPositions []uint64, number float64) *NumericField {
115	return NewNumericFieldWithIndexingOptions(name, arrayPositions, number, DefaultNumericIndexingOptions)
116}
117
118func NewNumericFieldWithIndexingOptions(name string, arrayPositions []uint64, number float64, options IndexingOptions) *NumericField {
119	numberInt64 := numeric.Float64ToInt64(number)
120	prefixCoded := numeric.MustNewPrefixCodedInt64(numberInt64, 0)
121	return &NumericField{
122		name:           name,
123		arrayPositions: arrayPositions,
124		value:          prefixCoded,
125		options:        options,
126		// not correct, just a place holder until we revisit how fields are
127		// represented and can fix this better
128		numPlainTextBytes: uint64(8),
129	}
130}
131