diff --git a/Gvisual/src/app/matchImei.java b/Gvisual/src/app/matchImei.java
index bf5d81c..8be1c5f 100644
--- a/Gvisual/src/app/matchImei.java
+++ b/Gvisual/src/app/matchImei.java
@@ -2,6 +2,8 @@
package app;
import java.sql.*;
+import java.util.HashMap;
+import java.util.Map;
/**
* Maps Bluetooth node identifiers to IMEI device identifiers in trace data.
@@ -12,6 +14,11 @@
* the sender node is empty. Only considers records with RSSI above a
* configurable threshold to filter out noise from distant devices.
*
+ * Performance: Device lookups use an in-memory {@link HashMap}
+ * (O(1) per lookup) instead of the previous nested ResultSet scan
+ * (O(devices) per event row), reducing overall complexity from
+ * O(events × devices) to O(events + devices).
+ *
* @author zalenix
*/
public class matchImei {
@@ -32,93 +39,119 @@ public class matchImei {
private static final String SELECT_SRCNODE_SQL =
"SELECT DISTINCT srcnode FROM event_3 WHERE sndrnode = '' AND rssi >= ?";
+ /**
+ * Loads the device_1 table into a HashMap for O(1) node→IMEI lookups.
+ *
+ * @param conn database connection
+ * @return map from node identifier to IMEI string
+ */
+ private static Map loadDeviceMap(Connection conn) throws SQLException {
+ Map deviceMap = new HashMap<>();
+ try (Statement stmt = conn.createStatement();
+ ResultSet rs = stmt.executeQuery("SELECT DISTINCT * FROM device_1")) {
+ while (rs.next()) {
+ String node = rs.getString(1);
+ String imei = rs.getString(2);
+ if (node != null && imei != null) {
+ deviceMap.put(node, imei);
+ }
+ }
+ }
+ System.out.println("device map loaded: " + deviceMap.size() + " entries");
+ return deviceMap;
+ }
+
+ /**
+ * Matches event nodes to IMEIs and batch-updates the database.
+ *
+ * @param deviceMap node→IMEI lookup map
+ * @param selectStmt prepared statement to fetch distinct nodes
+ * @param updateStmt prepared statement to update sndrimei
+ * @param nodeType label for logging ("sndrnode" or "srcnode")
+ * @param batchSize number of updates to accumulate before flushing
+ */
+ private static void matchAndUpdate(Map deviceMap,
+ PreparedStatement selectStmt,
+ PreparedStatement updateStmt,
+ String nodeType,
+ int batchSize) throws SQLException {
+ try (ResultSet rs = selectStmt.executeQuery()) {
+ int matched = 0;
+ int unmatched = 0;
+ int batchCount = 0;
+
+ while (rs.next()) {
+ String node = rs.getString(1);
+ String imei = deviceMap.get(node);
+
+ if (imei != null) {
+ matched++;
+ updateStmt.setString(1, imei);
+ updateStmt.setString(2, node);
+ updateStmt.addBatch();
+ batchCount++;
+
+ if (batchCount >= batchSize) {
+ updateStmt.executeBatch();
+ System.out.println(" flushed batch (" + matched + " matched so far)");
+ batchCount = 0;
+ }
+ } else {
+ unmatched++;
+ }
+ }
+
+ // Flush remaining
+ if (batchCount > 0) {
+ updateStmt.executeBatch();
+ }
+
+ System.out.println("all " + nodeType + " matched: "
+ + matched + " resolved, " + unmatched + " unmatched");
+ }
+ }
+
/**
* @param args the command line arguments
*/
public static void main(String[] args) throws Exception {
int Thres = -900;
+ int BATCH_SIZE = 500;
System.out.println("connecting...");
- try (Connection conn = Util.getAppConnection();
- Statement stmt1 = conn.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);
- PreparedStatement updateBySndrnode = conn.prepareStatement(UPDATE_BY_SNDRNODE_SQL);
- PreparedStatement updateBySrcnode = conn.prepareStatement(UPDATE_BY_SRCNODE_SQL);
- PreparedStatement selectSndrnode = conn.prepareStatement(SELECT_SNDRNODE_SQL,
- ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);
- PreparedStatement selectSrcnode = conn.prepareStatement(SELECT_SRCNODE_SQL,
- ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY)) {
-
- System.out.println("fetching device...");
- try (ResultSet rs_device = stmt1.executeQuery("SELECT DISTINCT * FROM device_1")) {
- System.out.println("device fetched...");
-
- // --- Match by sndrnode ---
- int numEventsDone;
- System.out.println("fetching event(sndrnode)...");
-
- selectSndrnode.setInt(1, Thres);
- try (ResultSet rs_event = selectSndrnode.executeQuery()) {
- rs_event.last();
- System.out.println("event(sndrnode) fetched..." + rs_event.getRow() + " entries");
- rs_event.first();
-
- numEventsDone = 0;
- while (rs_event.next()) {
- numEventsDone++;
- System.out.println("Done = " + numEventsDone);
- System.out.println("trying match imei with sndrnode " + rs_event.getString(1));
-
- rs_device.first();
- while (rs_device.next()) {
- if (rs_device.getString(1).equals(rs_event.getString(1))) {
- String imei = rs_device.getString(2);
- String sndrnode = rs_event.getString(1);
- System.out.println(imei);
- System.out.println("matched sndrnode " + sndrnode + "\n");
-
- updateBySndrnode.setString(1, imei);
- updateBySndrnode.setString(2, sndrnode);
- updateBySndrnode.executeUpdate();
- break;
- }
- }
- }
+ try (Connection conn = Util.getAppConnection()) {
+ // Disable auto-commit for batch performance
+ boolean origAutoCommit = conn.getAutoCommit();
+ conn.setAutoCommit(false);
+
+ try {
+ // Load device table into memory once — O(devices)
+ Map deviceMap = loadDeviceMap(conn);
+
+ try (PreparedStatement updateBySndrnode = conn.prepareStatement(UPDATE_BY_SNDRNODE_SQL);
+ PreparedStatement updateBySrcnode = conn.prepareStatement(UPDATE_BY_SRCNODE_SQL);
+ PreparedStatement selectSndrnode = conn.prepareStatement(SELECT_SNDRNODE_SQL);
+ PreparedStatement selectSrcnode = conn.prepareStatement(SELECT_SRCNODE_SQL)) {
+
+ // --- Match by sndrnode ---
+ System.out.println("matching by sndrnode...");
+ selectSndrnode.setInt(1, Thres);
+ matchAndUpdate(deviceMap, selectSndrnode, updateBySndrnode, "sndrnode", BATCH_SIZE);
+
+ // --- Match by srcnode ---
+ System.out.println("matching by srcnode...");
+ selectSrcnode.setInt(1, Thres);
+ matchAndUpdate(deviceMap, selectSrcnode, updateBySrcnode, "srcnode", BATCH_SIZE);
}
- System.out.println("all sndrnodes matched\n");
-
- // --- Match by srcnode ---
- System.out.println("fetching event(srcnode)...");
-
- selectSrcnode.setInt(1, Thres);
- try (ResultSet rs_event = selectSrcnode.executeQuery()) {
- rs_event.last();
- System.out.println("event(srcnode) fetched..." + rs_event.getRow() + " entries");
- rs_event.first();
-
- numEventsDone = 0;
- while (rs_event.next()) {
- numEventsDone++;
- System.out.println("Done = " + numEventsDone);
- System.out.println("trying match imei with srcnode " + rs_event.getString(1));
-
- rs_device.first();
- while (rs_device.next()) {
- if (rs_device.getString(1).equals(rs_event.getString(1))) {
- String imei = rs_device.getString(2);
- String srcnode = rs_event.getString(1);
- System.out.println(imei);
- System.out.println("matched srcnode " + srcnode + "\n");
-
- updateBySrcnode.setString(1, imei);
- updateBySrcnode.setString(2, srcnode);
- updateBySrcnode.executeUpdate();
- break;
- }
- }
- }
- }
- System.out.println("all srcnodes matched\n");
+
+ conn.commit();
+ System.out.println("all updates committed successfully");
+ } catch (Exception e) {
+ conn.rollback();
+ throw e;
+ } finally {
+ conn.setAutoCommit(origAutoCommit);
}
}
}