Эффективное хранение и поиск данных временных рядов с indexedDb - PullRequest
0 голосов
/ 20 февраля 2019

Я смотрю на хранение и получение данных временных рядов с помощью JavaScript в веб-браузере.Я ожидаю, что от 500 до 5000 элементов с плавающей запятой будут меняться с интервалом в секунду.При хранении каждый элемент будет иметь уникальное имя тега, одну и ту же метку времени (Date.now ()) и значение с плавающей запятой.

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

Моя проблема в том, что я не понимаюМодель данных indexedDb и API.Можно ли сохранить все мои новые значения (сгенерированные один раз в секунду для всех 1000 тегов) одним вызовом?

Я немного поэкспериментировал с Декси как оберткой вокруг indexedDb, и это был мой тестовый код:

async function start() {

  // Define database

  await Dexie.delete('trendDatabase');
  var db = new Dexie("trendDatabase");
  db.version(1).stores({
    trends: '++id,trendId,timestamp,value'
  });

  console.log ("Using Dexie v" + Dexie.semVer);

  // Query Database
  var result1 = await db.open();

  //add 1000 values for two trends

  var trendId1 = "FI-100";
  var trendId2 = "FI-200";
  var t1 = Date.now(); 
  for (var i=0; i<1000; i++) {
      var timestamp1 = t1 - (1000 + i) * 1000;
      var value1 = Math.sin(i/10)*8;
      var storeResult = await db.trends.add({trendId: trendId1, timestamp: timestamp1, value: value1});
      var value2 = Math.cos(i/100)*4;
      var storeResult = await db.trends.add({trendId: trendId2, timestamp: timestamp1, value: value1});
  }
  var t2 = Date.now();
  console.log("Took: ", t2 - t1);
  var t3 = Date.now();
  console.log("Took: ", t3 - t2);
  console.log(result3); 
  var result4 = db.delete();

}

Самая большая проблема заключается в том, насколько медленным является хранилище.На моем ноутбуке для хранения 2000 точек данных требуется 52 секунды (но для извлечения 1000 точек - всего 11 мс).На моем рабочем столе с оптановым хранилищем для хранения требуется около 2 секунд.В любом случае, это слишком медленно.Мне нужно иметь возможность сохранять данные раз в секунду, поэтому мне нужна скорость хранения <1000 мс, в идеале <100 мс. </p>

Существуют ли более эффективные способы структурирования данных временных рядов в indexedDb?

Одна из моих идей заключалась в том, что я могу хранить самые последние 100 точек данных для ВСЕХ трендов одновременно, а затем записывать блоки по 100 точек на отдельный тренд (в порядке ротации через каждый тренд), чтобы уменьшить количествовызовов записи с коэффициентом 100. Это также позволило бы получать последние данные (за последние 100 секунд), и в итоге я получал бы значения для всех 1000 тегов, когда мне нужно было только несколько из них, поэтому мне пришлось бы делатьнекоторая работа отфильтровывает несущественные данные.Этот подход, вероятно, работоспособен, но я хотел бы обратиться к сообществу, прежде чем пройти через все трудности, чтобы выяснить, есть ли лучшие подходы или какие-либо другие проекты / библиотеки для таких действий.

Ответы [ 2 ]

0 голосов
/ 20 февраля 2019

Хорошо, вы нашли Table.bulkAdd () для использования вместо Table.add () (видел ваш собственный ответ на вопрос)

Для части запроса я понял, что вы хотите включить и tag, и timeRangeв вашем запросе.

Я полагаю, что часть тега совпадает с trendId?

Если это так, я бы предложил перенести схему для использования составного индекса [trendId + timestamp] дляболее эффективные запросы.

Также рекомендовал бы оставить экземпляр db вне функции start ().Объявите его в модуле и экспортируйте.

db.js

// db.js
export const db = new Dexie('trendDatabase');

db.version(1).stores({
  trends: '++id,trendId,timestamp,value'
});// (Keep version 1 if you or your users have it installed)

// Migrate schema:
db.version(2).stores({
  trends: '++id, [trendId+timestamp]'
});

query.js

// query.js
import { db } from './db';

export function query(trendId, timeFrom, timeTo) {
  return db.trends
    .where('[trendId+timestamp]')
    .between([trendId, timeFrom], [trendId, timeTo])
    .toArray();
}

log.js

import { db } from './db';

export async function log(trends) {
  await db.trends.bulkAdd(trends);
}

Как видите, вам нужно только проиндексировать свойства, которые вы будете использовать в предложении where.Это не значит, что вы можете хранить другие свойства с каждым объектом.

0 голосов
/ 20 февраля 2019

Ну, я должен был провести еще какое-то исследование, прежде чем спрашивать.Похоже, что есть команда dexie.bulkAdd, которая решает мою проблему и уже более чем в 100 раз быстрее.

...