Ребята нужна помощь и это касается быстрого поиска. Пишу загрузку данных из DBF в Postgresql. Это должна быть не одноразовая загрузка, я буду ее использовать для обновления данных.
Алгоритм такой: беру каждую запись из DBF и ищу есть ли такая запись в базе Postgres, если есть, то просто обновляю поля в этой записи, если нет то добавляю новую запись. Я смог реализовать это путем двух вложенных циклов с полным перебором. Дела в том, что используя такой алгоритм, если обновлять справочник домов, в котором 400 записей, то при полном переборе будет 400*400 = 160000 итераций. У меня есть еще база лицевых счетов на 64000 записей, там будет 64000^2 = 4096 миллиарда итераций, и это будет длительный процесс
Я хочу чтобы был какой-нибудь индексированный поиск (без второго цикла с полным перебором), но не знаю как в Java это реализовать! Как это делается правильно в Java ?
Вот код метода (для работы с DBF использую классы Table, Record из библиотеки DANS DBF http://dans-dbf-lib.sourceforge.net/):
//загрузка справочника домов
private void domaLoad() {
String fileName = tfPath.getText() + '/' + "doma.dbf";
Table table = new Table(new File(fileName), "Cp866");
try {
Statement stmtAdd = Main.connectDB.getConnect().createStatement();
Statement stmt = Main.connectDB.getConnect().createStatement(ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE);
//открыть существующий файл DBF
table.open(IfNonExistent.ERROR);
String SQL = "SELECT id,ul,dom,korp,gek FROM doma";
ResultSet rs = stmt.executeQuery(SQL);
//перебрать таблицу DBF
Iterator<Record> iterator = table.recordIterator();
while (iterator.hasNext()) {
Record record = iterator.next();
String strUl = record.getStringValue("UL");
String strDom = record.getStringValue("DOM");
String strKorp = record.getStringValue("KORP");
String strGek = record.getStringValue("GEK");
//Поиск по ResultSet
boolean found = false;
rs.beforeFirst();
while (rs.next()) {
if (rs.getString("UL").equals(strUl)
&& rs.getString("DOM").equals(strDom)
&& rs.getString("KORP").equals(strKorp)) {
found = true;
break;
}
}
if (found) {
//обновить найденую запись
rs.updateString("GEK", strGek);
rs.updateRow();
} else {
//добавить новую запись
SQL = "INSERT INTO doma(ul,dom,korp,gek) "
+ "VALUES('" + strUl + "', '" + strDom + "', '" + strKorp + "', '" + strGek + "');";
stmtAdd.execute(SQL);
}
}
rs.close();
stmt.close();
stmtAdd.close();
} catch (Exception e) {
e.printStackTrace();
Main.eManager.show(e);
}
try {
table.close();
} catch (Exception e) {
e.printStackTrace();
Main.eManager.show(e);
}
}
короче я нуб, потому что мне не пришло в голову использовать класс HashMap для индексации. В качестве ключа использую Лицевой счет, в качестве значение - номер строки в ResultSet.
А результат по времени:
при условии полного перебора 10000 строк - 52 секунды
с использованием HashMap 10000 строк - 3 секунды
На обновлении всей таблицы ушло 18 секунд
Вот код:
//загрузка текущих лицевых счетов
private void lizLoad() {
long time1 = System.nanoTime();
ObservableList<Dom> listDom = Dom.getList();
String fileName = tfPath.getText() + '/' + "liz.dbf";
Table table = new Table(new File(fileName), "Cp866");
try {
Statement stmtAdd = Main.connectDB.getConnect().createStatement();
Statement stmt = Main.connectDB.getConnect().createStatement(ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE);
//открыть существующий файл
table.open(IfNonExistent.ERROR);
String SQL = "SELECT id,liz,sector,ul,dom,korp,kv,komn,dom_id,uch,tel FROM liz";
ResultSet rs = stmt.executeQuery(SQL);
//проиндексируем rs
HashMap<String, Integer> hashMap = new HashMap<>();
while (rs.next()) {
hashMap.put(rs.getString("liz"), rs.getRow());
}
//перебрать таблицу
Iterator<Record> iterator = table.recordIterator();
while (iterator.hasNext()) {
Record record = iterator.next();
String strLiz = record.getStringValue("LIZ");
String strSector = record.getStringValue("SECTOR");
String strUl = record.getStringValue("UL");
String strDom = record.getStringValue("DOM");
String strKorp = record.getStringValue("KORP");
String strKv = record.getStringValue("KV");
String strKomn = record.getStringValue("KOMN");
String strUch = record.getStringValue("UCH");
String strTel = record.getStringValue("TEL").trim();
//только городские телефоны, мобильные обнуляем
if (strTel.length() > 8)
strTel = "";
int idDom = 0;
for (Dom dom : listDom) {
if (dom.getUl().getUl().equals(strUl)
&& dom.getDom().equals(strDom)
&& dom.getKorp().equals(strKorp)) {
idDom = dom.getId();
break;
}
}
//содержит ли hashMap лицевой счет
if (hashMap.containsKey(strLiz)) {
//переходим на нужную запись
rs.absolute(hashMap.get(strLiz));
//обновить найденую запись
boolean update = false;
if (!rs.getString("sector").equals(strSector)) {
rs.updateString("sector", strSector);
update = true;
}
if (!rs.getString("ul").equals(strUl)) {
rs.updateString("ul", strUl);
update = true;
}
if (!rs.getString("dom").equals(strDom)) {
rs.updateString("dom", strDom);
update = true;
}
if (!rs.getString("korp").equals(strKorp)) {
rs.updateString("korp", strKorp);
update = true;
}
if (!rs.getString("kv").equals(strKv)) {
rs.updateString("kv", strKv);
update = true;
}
if (!rs.getString("komn").equals(strKomn)) {
rs.updateString("komn", strKomn);
update = true;
}
if (!rs.getString("uch").equals(strUch)) {
rs.updateString("uch", strUch);
update = true;
}
if (!rs.getString("tel").equals(strTel)) {
rs.updateString("tel", strTel);
update = true;
}
if (rs.getInt("dom_id") != idDom) {
if (idDom == 0)
rs.updateNull("dom_id");
else
rs.updateInt("dom_id", idDom);
update = true;
}
if (update)
rs.updateRow();
} else {
//нет лицевого счета в БД - добавить новую запись
if (idDom == 0)
SQL = "INSERT INTO liz(liz,sector,ul,dom,korp,kv,komn,uch,tel) "
+ "VALUES('" + strLiz + "', '" + strSector + "', '" + strUl + "', '" + strDom
+ "', '" + strKorp + "', '" + strKv + "', '" + strKomn
+ "', '" + strUch + "', '" + strTel + "');";
else
SQL = "INSERT INTO liz(liz,sector,ul,dom,korp,kv,komn,uch,tel,dom_id) "
+ "VALUES('" + strLiz + "', '" + strSector + "', '" + strUl + "', '" + strDom
+ "', '" + strKorp + "', '" + strKv + "', '" + strKomn
+ "', '" + strUch + "', '" + strTel + "', " + idDom + ");";
stmtAdd.execute(SQL);
}
}
rs.close();
stmt.close();
stmtAdd.close();
} catch (Exception e) {
e.printStackTrace();
Main.eManager.show(e);
}
try {
table.close();
} catch (Exception e) {
e.printStackTrace();
Main.eManager.show(e);
}
long time2 = System.nanoTime() - time1;
Main.setStatusBar(" Время выполнения " + time2 / 1_000_000_000 + "сек.");
}
Всем спасибо за помощь.
Виртуальный выделенный сервер (VDS) становится отличным выбором
Пытаюсь расширить адаптер для спиннера, написал класс включающий в себя проверку: находится ли в списке данных для спиннера нужная строка:
Есть ли возможность задать border-image только с одной стороны блока (не вокруг)? Например, если необходимо сделать тот же border-bottom: dotted, только с промежутком...