Almacén de valor-clave eficiente en memoria Java

No creo que haya nada en el JDK que haga esto.

Sin embargo, implementar tal cosa es una simple cuestión de programación. Aquí hay una tabla hash de dirección abierta con sondeo lineal, con claves y valores almacenados en matrices paralelas:

public class LongIntParallelHashMultimap {

    private static final long NULL = 0L;

    private final long[] keys;
    private final int[] values;
    private int size;

    public LongIntParallelHashMultimap(int capacity) {
        keys = new long[capacity];
        values = new int[capacity];
    }

    public void put(long key, int value) {
        if (key == NULL) throw new IllegalArgumentException("key cannot be " + NULL);
        if (size == keys.length) throw new IllegalStateException("map is full");

        int index = indexFor(key);
        while (keys[index] != NULL) {
            index = successor(index);
        }
        keys[index] = key;
        values[index] = value;
        ++size;
    }

    public int[] get(long key) {
        if (key == NULL) throw new IllegalArgumentException("key cannot be " + NULL);

        int index = indexFor(key);
        int count = countHits(key, index);

        int[] hits = new int[count];
        int hitIndex = 0;

        while (keys[index] != NULL) {
            if (keys[index] == key) {
                hits[hitIndex] = values[index];
                ++hitIndex;
            }
            index = successor(index);
        }

        return hits;
    }

    private int countHits(long key, int index) {
        int numHits = 0;
        while (keys[index] != NULL) {
            if (keys[index] == key) ++numHits;
            index = successor(index);
        }
        return numHits;
    }

    private int indexFor(long key) {
        // the hashing constant is (the golden ratio * Long.MAX_VALUE) + 1
        // see The Art of Computer Programming, section 6.4
        // the constant has two important properties:
        // (1) it is coprime with 2^64, so multiplication by it is a bijective function, and does not generate collisions in the hash
        // (2) it has a 1 in the bottom bit, so it does not add zeroes in the bottom bits of the hash, and does not generate (gratuitous) collisions in the index
        long hash = key * 5700357409661598721L;
        return Math.abs((int) (hash % keys.length));
    }

    private int successor(int index) {
        return (index + 1) % keys.length;
    }

    public int size() {
        return size;
    }

}

Tenga en cuenta que esta es una estructura de tamaño fijo. Tendrá que crearlo lo suficientemente grande como para contener todos sus datos: 110 millones de entradas para mí ocupan 1.32 GB. Cuanto más grande sea, más de lo que necesita para almacenar los datos, más rápido serán las inserciones y búsquedas. Encontré que para 110 millones de entradas, con un factor de carga de 0.5 (2.64 GB, el doble de espacio que el necesario), tomó un promedio de 403 nanosegundos para buscar una clave, pero con un factor de carga de 0.75 (1.76 GB, un tercero más espacio del necesario), tomó 575 nanosegundos. Disminuir el factor de carga por debajo de 0.5 generalmente no hace mucha diferencia, y de hecho, con un factor de carga de 0.33 (4.00 GB, tres veces más espacio del necesario), obtengo un tiempo promedio de 394 nanosegundos. Entonces, aunque tenga 5 GB disponibles, no lo use todo.

Tenga en cuenta también que el cero no está permitido como clave. Si esto es un problema, cambie el valor nulo para que sea otra cosa y rellene previamente la matriz de claves con eso en la creación.

Respuesta 1

Es una buena idea buscar bases de datos, porque para estos problemas están diseñados. En los últimos años, las bases de datos Key-Value se hicieron muy populares, por ejemplo, para servicios web (palabra clave "NoSQL"), por lo que debería encontrar algo.

La elección de una estructura de datos personalizada también depende si desea utilizar un disco duro para almacenar sus datos (y qué tan seguro debe ser) o si se pierde por completo al salir del programa.

Si se implementa manualmente y todo el db encaja en la memoria de manera algo sencilla, simplemente implementaría un hashmap en C. Crear una función hash que proporcione una dirección de memoria (bien extendida) a partir de un valor. Insertar allí o al lado si ya está asignado. Asignación y recuperación es entonces O (1). Si lo implementa en Java, tendrá una sobrecarga de 4 bytes para cada objeto (primitivo).

Respuesta: 2

Si debe usar Java, implemente su propia tabla hash / hashmap. Una propiedad importante de su tabla es usar una lista vinculada para manejar las colisiones. Por lo tanto, cuando realiza una búsqueda, puede devolver todos los elementos de la lista.

Respuesta: 3

Estoy usando Pdfbox para dibujar una línea en mi documento. Código: contentStream.drawLine (startX, startY, startX, endY); El resultado es una línea recta. Me pregunto ¿PdfBox puede dibujar líneas punteadas?

Estoy tratando de ejecutar un programa de muestra en Apache Flink en modo local. import org.apache.flink.api.common.functions.FlatMapFunction; import org.apache.flink.api.java.DataSet; import org.apache.flink ....

Después de cerrar una conexión de base de datos en Java, ¿puedo volver a abrirla? ¿O necesito volver a hacer DriverManager.getConnection ()?

Estoy usando String.split () para dividir una cadena. La cadena que recibo tiene esta estructura: [datos] <US> [datos] <US> donde <US> es el separador de unidad ASCII (código 0x1F). El código para dividir es ...