Задавайте вопросы, мы ответим
Вы не зашли.
Страниц: 1
Добрый день.
у меня имеется текстовый файл объемом 22 Гб. Из него мне нужно извлечь все ссылки вида <a href="sense">lemma</a>, из чего нужно потом составить словарь, где каждой lemma будут соответствовать senses, на которые она ссылалась и количество таких ссылок. Т. е. нужно построить словарь, в котором перечисляются все возможные смыслы (ссылки) соответствующие каждой лемме (видимой части ссылки) и указывается их количество. По предварительным подсчетам будет не менее 15 миллионов записей.
Для доступа к MySql я использую JDBC.
Структура базы данных следущая:
1) Таблица лемм (lemmas)
+----------+----------------+------+-----+---------+----------------+
| lemma_id | int(11) | NO | PRI | NULL | auto_increment |
| lemma | varbinary(255) | YES | UNI | NULL | |
| rate | int(11) | YES | | NULL | |
+----------+----------------+------+-----+---------+----------------+
2) Таблица смыслов (senses)
+----------+----------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+----------+----------------+------+-----+---------+----------------+
| sense_id | int(11) | NO | PRI | NULL | auto_increment |
| sense | varbinary(255) | YES | UNI | NULL | |
+----------+----------------+------+-----+---------+----------------+
3) Собственно словарь (dictionary)
| Field | Type | Null | Key | Default | Extra |
+----------+---------+------+-----+---------+-------+
| lemma_id | int(11) | NO | PRI | | |
| sense_id | int(11) | NO | PRI | | |
| quantity | int(11) | YES | | NULL | |
+----------+---------+------+-----+---------+-------+
Данные я заполняю следующим образом:
1) Создаю кэш - хеш-таблицу в оперативке, в которой содержится словарь. Когда свободной памяти становится меньше, чем 0.4 от той, что было выделено изначально для процесса, я начинаю записывать хеш в бд.
2) Создаю батч, в котором заполняются таблицы лемм и смыслов (простой INSERT IGNORE DUPLICATES). Выполняю executeBatch().
3) Для всех пар лемма-смысл, что хранятся в кэше в текстовом виде, извлекаю их id из соответствующих таблиц. Формирую батч для заполнения словаря.
4) Выполняю батч для заполнения словаря.
Шаг 3, естественно, самый трудоемкий. Есть ли шанс как-то ускорить дело? Разумна ли подобная организация таблиц/запросов или лучше изменить структуру БД?
Спасибо заранее за помощь.
Неактивен
Структура вполне нормальная, не думаю, что будут с ней какие-то проблемы. Если хотите немного
увеличить скорость занесения данных, можете временно отключить индексы на таблицах
(ALTER TABLE tablename DISABLE INDEX); при этом потеряется проверка уникальности (временно),
но если Ваша программа и так следит за этим, то проблем быть не должно.
Неактивен
Спасибо за ответ. Буду знать, что хотя бы со структурой у меня все в порядке
К сожалению, моя программа-заполнитель не может следить за проверкой уникальности. На данный момент она обработала 10 из 20 Гб и лемм у меня 10 652 384, а смыслов 9 899 298, я не могу держать это все в оперативной памяти, чтобы сверяться, потому что мне придется чаще очищать кэш, а следовательно чаще придется повторять шаг 3, а именно "Для всех пар лемма-смысл, что хранятся в кэше в текстовом виде, извлекаю их id из соответствующих таблиц." На последней итерации (когда у меня в сумме 20 миллионов лем и смыслов) это заняло 4 часа.
Мне очень не нравится этот шаг 3. Мне очень интересно, можно ли как-то оптимизировать нижеследующее?
///Делаю PreparedStatement:
java.sql.PreparedStatement statement = conn.prepareStatement("select senses.sense_id, lemmas.lemma_id from senses, lemmas where senses.sense=? and lemmas.lemma=?;");
***
//в цикле вытаскиваю из хеш таблицы смысл - szSense и лемму - szLemmaRaw и отправляю их в PreparedStatement
statement.setString(1, szSense);
statement.setString(2, szLemmaRaw);
try {
//выполняю PreparedStatement
rs = statement.executeQuery();
//получаю id леммы и смысла
rs.next();
int nSenId = rs.getInt("senses.sense_id");
int nLemId = rs.getInt("lemmas.lemma_id");
//формирую команду для их внесения в словарь, где nQuantity - сколько раз лемма встретилась в данном смысле (инициализуется выше, это не суть важно)
stDictUpdate.addBatch("INSERT INTO dictionary(lemma_id,sense_id,quantity) VALUES ('"+nLemId+"','"+nSenId+"','"+nQuantity+"')" +
"ON DUPLICATE KEY UPDATE quantity=quantity+"+nQuantity +";");
}
catch (SQLException e) {
System.out.println("[INFO] Error on lemma: "+szLemma);
e.printStackTrace();
}
****
// после окончания цикла выполняю батч
stDictUpdate.executeBatch();
conn.commit();
stDictUpdate.clearBatch();
stDictUpdate.close();
Неактивен
Честно говоря, не понял Ваш алгоритм. Конкретно — откуда берется nQuantity. Если вставлять
приходится все равно построчечно, то я бы сделал вообще хранимую процедуру вставки, которая
бы занималась всей необходимой работой на стороне сервера, а программа бы упростилась до
тупого запуска процедуры на каждую подходящую под регулярное выражение строку.
Процедуру какую-то такую
Неактивен
nQuantity - количество одинаковых пар лемма-смысл. т.е. в процедуре тогда будет написано
Отредактированно juni86 (27.07.2009 21:06:29)
Неактивен
Ну вот из Вашего куска кода просто совсем не понятно, откуда это число возникает
Неактивен
Хотелось просто привести выдержки только из тех мест, где явно идет работа с MySql, вот оно и потерялось
Неактивен
Страниц: 1