Запрос RethinkDB на основе нескольких временных меток в качестве вторичных индексов - PullRequest
4 голосов
/ 20 марта 2020

У меня есть RethinkDB с таблицей 'events', каждое событие имеет столбцы 'from' и 'to', обе являются временными метками.

Я хочу в основном запросить эту таблицу, возвращая все события, которые являются «активными» во временном окне, то есть столбец с находится перед концом временного окна, а конечный столбец - после начала временного окна (начало временного окна является текущим временем, а конец временное окно текущее время + 2 часа). По этой причине я создал вторичный индекс для обоих столбцов.

В идеале мне бы хотелось получать его в виде единого канала изменений, включающего любые изменения в событиях в реальном времени, а также выбирать события, которые становятся активными по мере продвижения времени , но из того, что я могу сказать, это невозможно, так как в соответствии с документами «Команда now () вычисляется один раз, когда сервер получает запрос» (исправьте меня, если я ошибаюсь), поэтому я прибегну к созданию нового changefeed каждый час, который запрашивает активные события в 2-часовом окне от текущего времени.

Теперь я сначала подумал, что буду использовать два между вызовами, например, так:

let currentEndpoint = moment().add(2, 'hours');

// query for active events
r
  .table('events')
  // event start is before end of window
  .between(new Date(1), currentEndpoint, {index: 'from'})
  // event end is after current time
  .between(new Date(), r.epochTime(1900266776))
  .run(connection)
  .then(res => {
    console.log(res)
  })
  .catch(e => {
    console.error(e);
  })

Что, по-видимому, не разрешено : ReqlQueryLogicError: Cannot perform multiple BETWEENs on the same tabl

Я понимаю, как можно было бы сделать это с помощью команды фильтра довольно легко, но, поскольку это основной способ запроса таблицы, я подумал, что было бы лучше использовать индексы, Есть ли способ создать этот запрос?


Визуальный пример

                       event2
                          \
                      _____\______
                     /            \
time: ---->---->---->---->---->---->---->---->---->---->----> ...
            \__/             \__/        /         \__/
    event1___/        event3__/         /   event5__/
                                event4_/


                  ^              ^ 
query window:     |______________|

expected results: [ event2, event3 ]

Воспроизводимая задача

Создание таблицы events -

r.tableCreate("events");
// { tables_created: 1, ... }

Добавить некоторые события. Для простоты концептуального подхода мы заботимся только о year, month и day. Решение проблемы для более детального времени, такого как hours или minutes, фактически совпадает

r.table("events").insert([
  { name: "fishing tourney"
  , from: r.time(2020, 1, 11, "Z")
  , to: r.time(2020, 1, 12, "Z")
  }
, { name: "cherry blossom"
  , from: r.time(2020, 4, 1, "Z")
  , to: r.time(2020, 4, 10, "Z")
  }
, { name: "fishing tourney"
  , from: r.time(2020, 4, 11, "Z")
  , to: r.time(2020, 4, 12, "Z")
  }
, { name: "bunny day"
  , from: r.time(2020, 4, 1, "Z")
  , to: r.time(2020, 4, 12, "Z")
  }
, { name: "fishing tourney"
  , from: r.time(2020, 7, 11, "Z")
  , to: r.time(2020, 7, 12, "Z")
  }
]);
// { inserted: 5, generated_keys: [ ... ], ... }

Создайте некоторый вторичный индекс -

r.table("events").indexCreate(
  "event_window",
  ???
);

При заданном диапазоне дат получить все события с пересекающимся окном событий -

const start = r.time(2020, 4, 8, "Z");   // April 8, 2020
const end = start.add(3 * 24 * 60 * 60); // April 11, 2020, 3 days later

// filter it?
r.table("events").filter(???)...

// use .between somehow?
r.table("events").between(???, ???, { index: "event_window" })

// some other technique?
r.table("events").eqJoin(???)
r.table("events").???

Перекрытия событий 8 апреля 2020 г. - 11 апреля 2020 г. -

// expected output
[ { name: "cherry blossom"
  , from: r.time(2020, 4, 1, "Z")
  , to: r.time(2020, 4, 10, "Z")
  }
, { name: "fishing tourney"
  , from: r.time(2020, 4, 11, "Z")
  , to: r.time(2020, 4, 12, "Z")
  }
]

Ответы [ 2 ]

2 голосов
/ 20 апреля 2020

События, которые вы будете возвращать в наборе результатов, попадают как минимум в один из этих наборов:

  1. Все события, закончившиеся в окне запроса.
  2. Все события, начавшиеся в окно запроса.

(события, начинающиеся и заканчивающиеся в окне запроса, попадают в оба набора)

Если вы проиндексировали свои атрибуты from и to, вы можете запросить All events that ended in query window, и объединить это с All events that started in query window. Вы по-прежнему можете использовать правильный индекс для каждого набора событий. Не забудьте дедуплицировать для событий, которые попадают в оба набора.

r.table("events").between(r.time(2020, 4, 8, "Z"), r.time(2020, 4, 11, "Z"), { index: "from", rightBound: "closed" }).union(
  r.table("events").between(r.time(2020, 4, 8, "Z"), r.time(2020, 4, 11, "Z"), { index: "to" })
).distinct()

Я не могу говорить о том, что это идиоматизм c или лучший способ сделать это, но мне пришлось использовать что-то подобное в прошлое.

0 голосов
/ 24 апреля 2020

Не знаю много о RethinkDB , так что просто сумасшедшая идея: может, геопространственный индекс может помочь? Определенно не идиоматический c, но есть getIntersecting

Получить все документы, где данный геометрический объект пересекается с геометрическим объектом запрошенного геопространственного индекса.

И вы можете рассматривать интервалы дат событий и интервал окна как линии (или тонкие прямоугольники).

...