sql >> Base de Datos >  >> RDS >> Mysql

Libpuzzle ¿Indización de millones de imágenes?

Entonces, echemos un vistazo al ejemplo que dan e intentemos expandirlo.

Supongamos que tiene una tabla que almacena información relacionada con cada imagen (ruta, nombre, descripción, etc.). En esa tabla, incluirá un campo para la firma comprimida, calculada y almacenada cuando llene inicialmente la base de datos. Definamos esa tabla así:

CREATE TABLE images (
    image_id INTEGER NOT NULL PRIMARY KEY,
    name TEXT,
    description TEXT,
    file_path TEXT NOT NULL,
    url_path TEXT NOT NULL,
    signature TEXT NOT NULL
);

Cuando calcule inicialmente la firma, también calculará una cantidad de palabras de la firma:

// this will be run once for each image:
$cvec = puzzle_fill_cvec_from_file('img1.jpg');
$words = array();
$wordlen = 10; // this is $k from the example
$wordcnt = 100; // this is $n from the example
for ($i=0; $i<min($wordcnt, strlen($cvec)-$wordlen+1); $i++) {
    $words[] = substr($cvec, $i, $wordlen);
}

Ahora puedes poner esas palabras en una tabla, definida así:

CREATE TABLE img_sig_words (
    image_id INTEGER NOT NULL,
    sig_word TEXT NOT NULL,
    FOREIGN KEY (image_id) REFERENCES images (image_id),
    INDEX (image_id, sig_word)
);

Ahora inserte en esa tabla, anteponiendo el índice de posición de donde se encontró la palabra, para que sepa cuando una palabra coincide que coincidió en el mismo lugar en la firma:

// the signature, along with all other data, has already been inserted into the images
// table, and $image_id has been populated with the resulting primary key
foreach ($words as $index => $word) {
    $sig_word = $index.'__'.$word;
    $dbobj->query("INSERT INTO img_sig_words (image_id, sig_word) VALUES ($image_id,
        '$sig_word')"); // figure a suitably defined db abstraction layer...
}

Con sus datos así inicializados, puede capturar imágenes con palabras coincidentes con relativa facilidad:

// $image_id is set to the base image that you are trying to find matches to
$dbobj->query("SELECT i.*, COUNT(isw.sig_word) as strength FROM images i JOIN img_sig_words
    isw ON i.image_id = isw.image_id JOIN img_sig_words isw_search ON isw.sig_word =
    isw_search.sig_word AND isw.image_id != isw_search.image_id WHERE
    isw_search.image_id = $image_id GROUP BY i.image_id, i.name, i.description,
    i.file_path, i.url_path, i.signature ORDER BY strength DESC");

Podría mejorar la consulta agregando un HAVING cláusula que requiere una strength mínima , lo que reduce aún más su conjunto de coincidencias.

No garantizo que esta sea la configuración más eficiente, pero debería ser más o menos funcional para lograr lo que está buscando.

Básicamente, dividir y almacenar las palabras de esta manera le permite realizar una verificación de distancia aproximada sin tener que ejecutar una función especializada en las firmas.