All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.twitter.storehaus.algebra.query.TimeRangeQuery.scala Maven / Gradle / Ivy

There is a newer version: 0.15.0-RC1
Show newest version
/*
 * Copyright 2013 Twitter Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may
 * not use this file except in compliance with the License. You may obtain
 * a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.twitter.storehaus.algebra.query

import scala.annotation.tailrec

// end is not included: [start, end)
case class TimeRange(start: Long, end: Long)
/*
 *  bucket is which of the exponentially size buckets we are in
 * timeInBuckets = time / (this bucket size)
 */
case class BucketTime(bucket: Int, timeInBuckets: Long)

/** A query strategy for time with exponentially expanding buckets of time.
 */
class TimestampStrategy(minBucketMs: Long,
  maxBucketMs: Long, factor: Int) extends QueryStrategy[TimeRange, Long, BucketTime] {

  val buckets = Iterator.iterate(minBucketMs) { _ * factor }
    .takeWhile { _ < maxBucketMs}
    .zipWithIndex
    .toList

  // Maps start/end to the the greatest lower bound
  def normalize(in: TimeRange): TimeRange =
    TimeRange(toBoundary(in.start), toBoundary(in.end))

  protected def toBoundary(time: Long): Long =
    (time / minBucketMs) * minBucketMs

  def query(thisquery: TimeRange) = {
    // find the minimal covering set of [start,end]
    @tailrec
    def queryRec(q: TimeRange, acc: Set[BucketTime]): Set[BucketTime] = {
      if(q.start >= q.end) acc
      else {
        val (bucketSize, idx) = buckets.dropWhile { case (bucketSize, _) =>
          (q.start % bucketSize == 0) && (q.start + bucketSize <= q.end)
        }.head
        queryRec(TimeRange(q.start + bucketSize, q.end),
          acc + BucketTime(idx, q.start/bucketSize))
      }
    }
    // Kick off the recursion
    queryRec(thisquery, Set[BucketTime]())
  }

  def index(ts: Long) =
    buckets.map { case (bucketSize, idx) => BucketTime(idx, ts/bucketSize) }.toSet
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy