PostgreSQL
 sql >> Datenbank >  >> RDS >> PostgreSQL

Leistung der Berechnung und Sortierung von Delta E (CIE Lab) in SQL

Zwei Dinge:1) Sie nutzen die Datenbank nicht in vollem Umfang und 2) Ihr Problem ist ein großartiges Beispiel für eine benutzerdefinierte PostgreSQL-Erweiterung. Hier ist der Grund.

Sie verwenden die Datenbank nur als Speicher und speichern Farben als Floats. In Ihrer aktuellen Konfiguration muss die Datenbank unabhängig von der Art der Abfrage immer alle Werte überprüfen (einen sequentiellen Scan durchführen). Dies bedeutet viel IO und viel Berechnung für wenige zurückgegebene Übereinstimmungen. Sie versuchen, die nächsten N Farben zu finden, daher gibt es einige Möglichkeiten, wie Sie vermeiden können, Berechnungen für alle Daten durchzuführen.

Einfache Verbesserung

Am einfachsten ist es, Ihre Berechnungen auf eine kleinere Teilmenge von Daten zu beschränken. Sie können davon ausgehen, dass der Unterschied größer ist, wenn sich die Komponenten stärker unterscheiden. Wenn Sie einen sicheren Unterschied zwischen den Komponenten finden, bei denen die Ergebnisse immer unangemessen sind, können Sie diese Farben vollständig ausschließen, indem Sie ranged WHERE mit btree-Indizes verwenden. Aufgrund der Natur des L*a*b-Farbraums wird dies jedoch wahrscheinlich Ihre Ergebnisse verschlechtern.

Erstellen Sie zuerst die Indizes:

CREATE INDEX color_lab_l_btree ON color USING btree (lab_l);
CREATE INDEX color_lab_a_btree ON color USING btree (lab_a);
CREATE INDEX color_lab_b_btree ON color USING btree (lab_b);

Dann habe ich Ihre Abfrage so angepasst, dass sie eine WHERE-Klausel enthält, um nur Farben zu filtern, bei denen sich eine der Komponenten um höchstens 20 unterscheidet.

Aktualisierung: Nach nochmaligem Hinsehen wird das Hinzufügen einer Grenze von 20 sehr wahrscheinlich die Ergebnisse verschlechtern, da ich mindestens einen Punkt im Raum gefunden habe, für den dies gilt.:

SELECT 
    c.rgb_r, c.rgb_g, c.rgb_b,
    DELTA_E_CIE2000(
        25.805780252087963, 53.33446637366859, -45.03961353720049, 
        c.lab_l, c.lab_a, c.lab_b,
        1.0, 1.0, 1.0) AS de2000
FROM color c 
WHERE 
    c.lab_l BETWEEN 25.805780252087963 - 20 AND 25.805780252087963 + 20 
    AND c.lab_a BETWEEN 53.33446637366859 - 20 AND 53.33446637366859 + 20 
    AND c.lab_b BETWEEN -45.03961353720049 - 20 AND -45.03961353720049 + 20 
ORDER BY de2000 ;

Ich habe die Tabelle mit 100000 zufälligen Farben mit Ihrem Skript gefüllt und getestet:

Zeit ohne Indizes:44006.851 ms

Zeit mit Indizes und Bereichsabfrage:1293.092 ms

Sie können diese WHERE-Klausel zu delta_e_cie1976_query hinzufügen Auch bei meinen Zufallsdaten sinkt die Abfragezeit von ~110 ms auf ~22 ms.

Übrigens:Ich habe die Zahl 20 empirisch erhalten:Ich habe es mit 10 versucht, aber nur 380 Datensätze erhalten, was ein wenig niedrig erscheint und einige bessere Optionen ausschließen könnte, da das Limit 100 ist. Mit 20 war der vollständige Satz 2900 Zeilen und man kann ziemlich sein sicher, dass die engsten Übereinstimmungen dort sein werden. Ich habe den DELTA_E_CIE2000- oder L*a*b*-Farbraum nicht im Detail untersucht, daher muss der Schwellenwert möglicherweise entlang verschiedener Komponenten angepasst werden, damit dies tatsächlich zutrifft, aber das Prinzip des Ausschlusses nicht interessanter Daten gilt.

Delta E CIE 2000 in C umschreiben

Wie Sie bereits sagten, ist Delta E CIE 2000 komplex und für die Implementierung in SQL ziemlich ungeeignet. Es verbraucht derzeit etwa 0,4 ms pro Anruf auf meinem Laptop. Die Implementierung in C sollte dies erheblich beschleunigen. PostgreSQL weist SQL-Funktionen Standardkosten als 100 und C-Funktionen als 1 zu. Ich schätze, das basiert auf echter Erfahrung.

Aktualisierung: Da dies auch einen meiner Juckreize kratzt, habe ich die Delta-E-Funktionen aus dem Colormath-Modul in C als PostgreSQL-Erweiterung neu implementiert, verfügbar unter PGXN . Damit sehe ich eine etwa 150-fache Beschleunigung für CIE2000, wenn alle Datensätze aus der Tabelle mit 100.000 Datensätzen abgefragt werden.

Mit dieser C-Funktion erhalte ich Abfragezeiten zwischen 147 ms und 160 ms für 100.000 Farben. Mit extra WHERE beträgt die Abfragezeit etwa 20 ms, was für mich durchaus akzeptabel erscheint.

Beste, aber fortschrittlichste Lösung

Da Ihr Problem jedoch die Suche nach N nächsten Nachbarn im dreidimensionalen Raum ist, könnten Sie die K-Nearest-Neighbor-Indizierung verwenden, die in PostgreSQL seit Version 9.1 .

Damit das funktioniert, würden Sie L*a*b*-Komponenten in einen Würfel . Diese Erweiterung unterstützt noch keinen Distanzoperator ( es ist in Arbeit ), aber selbst wenn dies der Fall wäre, würde es keine Delta-E-Entfernungen unterstützen und Sie müssten es als C-Erweiterung neu implementieren.

Dies bedeutet die Implementierung der GiST-Indexoperatorklasse (btree_gist PostgreSQL-Erweiterung ). in contrib tut dies), um die Indizierung nach Delta-E-Abständen zu unterstützen. Das Gute daran ist, dass Sie dann verschiedene Operatoren für verschiedene Versionen von Delta E verwenden können, z. <-> für Delta E CIE 2000 und <#> für Delta E CIE 1976 und Abfragen wären wirklich sehr schnell für kleines LIMIT sogar mit Delta E CIE 2000.

Am Ende kann es davon abhängen, was Ihre (geschäftlichen) Anforderungen und Einschränkungen sind.