Индексированный поиск в JAVA

210
30 июля 2018, 01:50

Ребята нужна помощь и это касается быстрого поиска. Пишу загрузку данных из 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);
    }
}
Answer 1

короче я нуб, потому что мне не пришло в голову использовать класс 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 + "сек.");
}

Всем спасибо за помощь.

READ ALSO
Ошибка в расширении класса ArrayAdapter

Ошибка в расширении класса ArrayAdapter

Пытаюсь расширить адаптер для спиннера, написал класс включающий в себя проверку: находится ли в списке данных для спиннера нужная строка:

164
Авторизация и аутентификация Servlet

Авторизация и аутентификация Servlet

День добрыйПодскажите пожалуйста в каком направлении идти

215
Border-image с одной стороны блока

Border-image с одной стороны блока

Есть ли возможность задать border-image только с одной стороны блока (не вокруг)? Например, если необходимо сделать тот же border-bottom: dotted, только с промежутком...

219