sql >> Databasteknik >  >> RDS >> Mysql

Libpuzzle Indexera miljontals bilder?

Så låt oss ta en titt på exemplet de ger och försöka utöka.

Låt oss anta att du har en tabell som lagrar information om varje bild (sökväg, namn, beskrivning, etc). I den tabellen kommer du att inkludera ett fält för den komprimerade signaturen, beräknad och lagrad när du först fyller i databasen. Låt oss definiera den tabellen så här:

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
);

När du först beräknar signaturen kommer du också att beräkna ett antal ord från signaturen:

// 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);
}

Nu kan du lägga dessa ord i en tabell, definierad så här:

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)
);

Nu infogar du i den tabellen, före positionsindexet för var ordet hittades, så att du vet när ett ord matchar att det matchade på samma plats i signaturen:

// 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...
}

Din data initialiserad på så sätt kan du ta bilder med matchande ord relativt enkelt:

// $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");

Du kan förbättra frågan genom att lägga till en HAVING klausul som kräver en minsta strength , vilket ytterligare minskar din matchningsuppsättning.

Jag garanterar inte att detta är den mest effektiva installationen, men den bör vara ungefär funktionell för att uppnå det du letar efter.

Genom att dela upp och lagra orden på detta sätt kan du i princip göra en grov avståndskontroll utan att behöva köra en specialiserad funktion på signaturerna.



  1. mysql match mot flera ord

  2. Hur får man mysql slumpmässigt heltalsintervall?

  3. Hur DAYOFWEEK() fungerar i MariaDB

  4. Maximera effektiviteten av databasfrågor för MySQL - del två