You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

159 lines
4.2 KiB

  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. package document
  15. import (
  16. "fmt"
  17. "math"
  18. "reflect"
  19. "time"
  20. "github.com/blevesearch/bleve/analysis"
  21. "github.com/blevesearch/bleve/numeric"
  22. "github.com/blevesearch/bleve/size"
  23. )
  24. var reflectStaticSizeDateTimeField int
  25. func init() {
  26. var f DateTimeField
  27. reflectStaticSizeDateTimeField = int(reflect.TypeOf(f).Size())
  28. }
  29. const DefaultDateTimeIndexingOptions = StoreField | IndexField | DocValues
  30. const DefaultDateTimePrecisionStep uint = 4
  31. var MinTimeRepresentable = time.Unix(0, math.MinInt64)
  32. var MaxTimeRepresentable = time.Unix(0, math.MaxInt64)
  33. type DateTimeField struct {
  34. name string
  35. arrayPositions []uint64
  36. options IndexingOptions
  37. value numeric.PrefixCoded
  38. numPlainTextBytes uint64
  39. }
  40. func (n *DateTimeField) Size() int {
  41. return reflectStaticSizeDateTimeField + size.SizeOfPtr +
  42. len(n.name) +
  43. len(n.arrayPositions)*size.SizeOfUint64
  44. }
  45. func (n *DateTimeField) Name() string {
  46. return n.name
  47. }
  48. func (n *DateTimeField) ArrayPositions() []uint64 {
  49. return n.arrayPositions
  50. }
  51. func (n *DateTimeField) Options() IndexingOptions {
  52. return n.options
  53. }
  54. func (n *DateTimeField) Analyze() (int, analysis.TokenFrequencies) {
  55. tokens := make(analysis.TokenStream, 0)
  56. tokens = append(tokens, &analysis.Token{
  57. Start: 0,
  58. End: len(n.value),
  59. Term: n.value,
  60. Position: 1,
  61. Type: analysis.DateTime,
  62. })
  63. original, err := n.value.Int64()
  64. if err == nil {
  65. shift := DefaultDateTimePrecisionStep
  66. for shift < 64 {
  67. shiftEncoded, err := numeric.NewPrefixCodedInt64(original, shift)
  68. if err != nil {
  69. break
  70. }
  71. token := analysis.Token{
  72. Start: 0,
  73. End: len(shiftEncoded),
  74. Term: shiftEncoded,
  75. Position: 1,
  76. Type: analysis.DateTime,
  77. }
  78. tokens = append(tokens, &token)
  79. shift += DefaultDateTimePrecisionStep
  80. }
  81. }
  82. fieldLength := len(tokens)
  83. tokenFreqs := analysis.TokenFrequency(tokens, n.arrayPositions, n.options.IncludeTermVectors())
  84. return fieldLength, tokenFreqs
  85. }
  86. func (n *DateTimeField) Value() []byte {
  87. return n.value
  88. }
  89. func (n *DateTimeField) DateTime() (time.Time, error) {
  90. i64, err := n.value.Int64()
  91. if err != nil {
  92. return time.Time{}, err
  93. }
  94. return time.Unix(0, i64).UTC(), nil
  95. }
  96. func (n *DateTimeField) GoString() string {
  97. return fmt.Sprintf("&document.DateField{Name:%s, Options: %s, Value: %s}", n.name, n.options, n.value)
  98. }
  99. func (n *DateTimeField) NumPlainTextBytes() uint64 {
  100. return n.numPlainTextBytes
  101. }
  102. func NewDateTimeFieldFromBytes(name string, arrayPositions []uint64, value []byte) *DateTimeField {
  103. return &DateTimeField{
  104. name: name,
  105. arrayPositions: arrayPositions,
  106. value: value,
  107. options: DefaultDateTimeIndexingOptions,
  108. numPlainTextBytes: uint64(len(value)),
  109. }
  110. }
  111. func NewDateTimeField(name string, arrayPositions []uint64, dt time.Time) (*DateTimeField, error) {
  112. return NewDateTimeFieldWithIndexingOptions(name, arrayPositions, dt, DefaultDateTimeIndexingOptions)
  113. }
  114. func NewDateTimeFieldWithIndexingOptions(name string, arrayPositions []uint64, dt time.Time, options IndexingOptions) (*DateTimeField, error) {
  115. if canRepresent(dt) {
  116. dtInt64 := dt.UnixNano()
  117. prefixCoded := numeric.MustNewPrefixCodedInt64(dtInt64, 0)
  118. return &DateTimeField{
  119. name: name,
  120. arrayPositions: arrayPositions,
  121. value: prefixCoded,
  122. options: options,
  123. // not correct, just a place holder until we revisit how fields are
  124. // represented and can fix this better
  125. numPlainTextBytes: uint64(8),
  126. }, nil
  127. }
  128. return nil, fmt.Errorf("cannot represent %s in this type", dt)
  129. }
  130. func canRepresent(dt time.Time) bool {
  131. if dt.Before(MinTimeRepresentable) || dt.After(MaxTimeRepresentable) {
  132. return false
  133. }
  134. return true
  135. }