Как мне сохранить данные на диске, произвольно обновлять их и эффективно передавать обратно в оперативную память?

StackOverflow https://stackoverflow.com/questions/1274562

Вопрос

Мне нужно хранить на диске до десятков или даже сотен миллионов фрагментов данных.Каждый фрагмент данных содержит такую информацию, как:

id=23425
browser=firefox
ip-address=10.1.1.1
outcome=1.0

Новые фрагменты данных могут добавляться со скоростью до 1 в миллисекунду.

Таким образом, это относительно простой набор пар ключ-значение, где значениями могут быть строки, целые числа или числа с плавающей запятой.Иногда мне может потребоваться обновить фрагмент данных с определенным идентификатором, изменив поле флага с 0 на 1.Другими словами, мне нужно иметь возможность выполнять случайный поиск ключей по идентификатору и изменять данные (на самом деле только поле "результат" с плавающей запятой - поэтому мне никогда не нужно будет изменять размер значения).

Другое требование заключается в том, что мне нужно иметь возможность эффективно передавать эти данные с диска (порядок не особенно важен).Это означает, что головке жесткого диска не нужно прыгать по диску, чтобы прочитать данные, скорее они должны считываться последовательными дисковыми блоками.

Я пишу это на Java.

Я думал об использовании встроенной базы данных, но DB4O - это не вариант, поскольку это GPL, а остальной мой код - нет.Я также беспокоюсь об эффективности использования встроенной базы данных SQL, учитывая накладные расходы на перевод в SQL-запросы и из них.

У кого-нибудь есть какие-нибудь идеи?Могу ли я создать собственное решение для этого (где я имею дело непосредственно с ByteBuffers и обрабатываю поиск идентификатора)?

Это было полезно?

Решение 7

В конце концов я решил записывать данные на диск по мере их поступления, а также сохранять их в памяти, где я могу их обновлять.Через некоторое время я записываю данные на диск и удаляю журнал.

Другие советы

Как насчет H2Лицензия должно сработать на вас.

  • Вы можете использовать H2 бесплатно.Вы можете интегрировать его в свое приложение (включая коммерческие приложения), и вы можете распространять его.
  • Файлы , содержащие только ваш код, не подпадают под действие этой лицензии (она "пригодна для использования в коммерческих целях").
  • Изменения в исходном коде H2 должны быть опубликованы.
  • Вам не нужно предоставлять исходный код H2, если вы этого не делали что-либо изменять.

Я получаю

1000000 вставка за 22492 мс (44460,252534234394 строки в секунду)

100000 обновлений за 9565 мс (10454,783063251438 строк в секунду)

От

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.Random;


/**
 * @author clint
 *
 */
public class H2Test {

  static int testrounds = 1000000;

  public static void main(String[] args) {
    try {
      Class.forName("org.h2.Driver");

    Connection conn = DriverManager.
        getConnection("jdbc:h2:/tmp/test.h2", "sa", "");
    // add application code here
    conn.createStatement().execute("DROP TABLE IF EXISTS TEST");
    conn.createStatement().execute("CREATE TABLE IF NOT EXISTS TEST(id INT PRIMARY KEY, browser VARCHAR(64),ip varchar(16), outcome real)"); 
    //conn.createStatement().execute("CREATE INDEX IDXall ON TEST(id,browser,ip,outcome");


    PreparedStatement ps = conn.prepareStatement("insert into TEST (id, browser, ip, outcome) values (?,?,?,?)");
    long time = System.currentTimeMillis();
    for ( int i = 0; i < testrounds; i++ ) {
      ps.setInt(1,i);
      ps.setString(2,"firefox");
      ps.setString(3,"000.000.000.000");
      ps.setFloat(4,0);
      ps.execute();
    }
    long last = System.currentTimeMillis() ;
    System.out.println( testrounds + " insert in " + (last - time) + "ms (" + ((testrounds)/((last - time)/1000d)) + " row/sec)" );

    ps.close();
    ps = conn.prepareStatement("update TEST set outcome = 1 where id=?");
    Random random = new Random();
    time = System.currentTimeMillis();

    /// randomly updadte 10% of the entries
    for ( int i = 0; i < testrounds/10; i++ ) {
      ps.setInt(1,random.nextInt(testrounds));
      ps.execute();
    }

    last = System.currentTimeMillis();
    System.out.println( (testrounds/10) + " updates in " + (last - time) + "ms (" + ((testrounds/10)/((last - time)/1000d)) + " row/sec)" );

    conn.close();

    } catch (ClassNotFoundException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    } catch (SQLException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    }
  }

}

СУБД JDBM это отличная встроенная база данных для Java (и не такая обремененная лицензированием, как Java-версия Berkley).Это стоило бы попробовать.Если вам не нужны гарантии ACID (т.е.вы согласны с повреждением базы данных в случае сбоя), отключите диспетчер транзакций (значительно увеличивает скорость).

Я думаю, вы добились бы гораздо большего успеха, написав что-то, что кэширует наиболее активные записи в памяти и ставит изменения данных в очередь для вставки в базу данных с низким приоритетом.

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

Вы могли бы попробовать Беркли БД который теперь принадлежит Oracle.У них есть лицензии с открытым исходным кодом и коммерческие лицензии.Он использует модель Ключ / значение (с возможностью создания индексов, если требуются другие формы запросов).Существует чистая версия Java и нативная версия с привязками Java.

http://www.zentus.com/sqlitejdbc/

База данных SQLite (общественное достояние), соединитель JDBC с лицензией BSD, нативный для целого ряда платформ (OSX, Linux, Windows), эмуляция для остальных.

Вы можете использовать Apache Derby (или JavaDB), который поставляется в комплекте с JDK.Однако, если СУБД не обеспечивает требуемой скорости, вы можете самостоятельно реализовать определенную файловую структуру.Если требуется просто точный поиск ключа, вы можете использовать хэш-файл для его реализации.Хэш-файл - это самая быстрая файловая структура для таких требований (намного быстрее, чем файловые структуры общего назначения, такие как B-деревья и сетки, которые используются в DBS).Это также обеспечивает приемлемую эффективность потоковой передачи.

Вы ознакомились с базой данных Oracle 'TimesTen'?Это база данных в памяти, которая должна быть очень высокопроизводительной.Не знаю о затратах / лицензиях и т.д., но загляните на сайт Oracles и найдите его.Загрузка Eval должна быть доступна.

Я бы также взглянул, есть ли что-нибудь существующее на основе EHCache или JCS, что могло бы помочь.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top