sql >> Database >  >> RDS >> Mysql

Libpuzzle Miljoenen plaatjes indexeren?

Laten we dus eens kijken naar het voorbeeld dat ze geven en proberen uit te breiden.

Laten we aannemen dat je een tabel hebt die informatie opslaat met betrekking tot elke afbeelding (pad, naam, beschrijving, enz.). In die tabel neemt u een veld op voor de gecomprimeerde handtekening, berekend en opgeslagen wanneer u de database voor het eerst vult. Laten we die tabel als volgt definiëren:

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

Wanneer u in eerste instantie de handtekening berekent, gaat u ook een aantal woorden uit de handtekening berekenen:

// 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 kunt u die woorden in een tabel plaatsen, als volgt gedefinieerd:

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 voeg je in die tabel in, voor de positie-index van waar het woord werd gevonden, zodat je weet wanneer een woord overeenkomt met het op dezelfde plaats in de handtekening:

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

Uw gegevens zijn zo geïnitialiseerd, u kunt relatief eenvoudig afbeeldingen met overeenkomende woorden pakken:

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

U kunt de zoekopdracht verbeteren door een HAVING . toe te voegen clausule die een minimale strength vereist , waardoor uw bijpassende set verder wordt verminderd.

Ik kan niet garanderen dat dit de meest efficiënte setup is, maar het zou ongeveer functioneel moeten zijn om te bereiken wat je zoekt.

Kortom, door de woorden op deze manier te splitsen en op te slaan, kunt u een ruwe afstandscontrole uitvoeren zonder dat u een gespecialiseerde functie op de handtekeningen hoeft uit te voeren.



  1. Mysql externe sleutel door niet-unieke sleutel - hoe is dat mogelijk?

  2. Hoe maak ik verbinding met een MSSQL-database met behulp van Perl's DBI-module in Windows?

  3. Is het mogelijk om een ​​door komma's gescheiden kolom op te vragen voor een specifieke waarde?

  4. Is uw database beveiligd? Denk opnieuw