Ähnliche Begriffe finden Suchfunktionen haben Sie sicher in viele Ihrer Datenbanken eingebaut. Der Benutzer soll über ein Textfeld etwa den Stammdatensatz eines Kunden finden. Solange er die Schreibweise des Nachnamens oder einen Teil davon kennt, stellt Sie die Programmierung über SQL-Statements vor keine größeren Herausforderungen. Was aber, wenn kein Herr "Maier" unter den Kunden gefunden wird, weil sich dieser tatsächlich "Meyer" schreibt? Hier helfen fehlertolerante Suchalgorithmen weiter, die in diesem Beitrag kurz dargestellt sind. Um nach Begriffen in Textfeldern von Tabellen zu suchen, bietet sich in Access der LIKE-Oper ator an. Damit ist es immerhin möglich, Teil-Strings mit Wildcards (* oder %) zu finden. Nur reicht das in all jenen Fällen nicht aus, in denen nach ähnlichen Begriffen gesucht werden soll - eine Aufgabe, die sich häufig stellt. Dann ist es notwendig, angepasste Routinen zu entwickeln, die zwei Strings nach Ähnlichkeit vergleichen können - um VBA kommen Sie hier nicht herum, da JET keine entsprechenden Funktionen kennt. Selbst dann, wenn Sie als Backend einen SQL Server einsetzen und in Views oder Stored Procedures mit der Vergleichsfunktion Soundex arbeiten, wird Sie das Ergebnis ernüchtern. Damit kommt man meist nicht weit, weil die gängigen Soundex - oder Metaphone -Implementationen dieser Server in der Regel nur einen Wert True oder False für den Vergleich zurückgeben, nicht aber den Grad der Übereinstimmung zweier Begriffe etwa über einen variablen Zahlenwert. Der Soundex-Algorithmus kodiert jeden der beiden Begriffe annähernd phonetisch in einen 4-Zeichencode und gibt dann True zurück, wenn diese beiden Codes genau identisch sind. Selbst dann, wenn Sie JET über eine VBA-Funktion das unzulängliche Soundex beibringen, ist unbefriedigend, dass ein derartiger Code in VBA sehr langsam arbeitet - VB ist nicht 1 / 5
sonderlich schnell, wenn es um String-Routinen geht, weil es im Allgemeinen für jeden produzierten Teilstring neuen Speicher alloziert und wieder frei gibt. Um schnelle externe Komponenten kommen Sie deshalb selten herum, wenn Ihnen an guter Performance gelegen ist. Externe Komponente Daher habe ich die Vergleichsroutinen in eine in Borland Delphi entwickelte DLL gepackt, deren eingebaute Funktionen weitaus flotter sind, als entsprechende VBA-Pendants. Die DLL ist in den Windows-Systempfad zu kopieren (z.b. c:windowssystem32) und stellt dann folgende Funktionen bereit: Public Declare Function AreSimilar Lib "mosssoft_w" (ByVal lpstring1 As String, _ Public Declare Function SoundExSimilar Lib "mosssoft_w" (ByVal lpstring1 As String, _ Public Declare Function MetaPhoneSimilar Lib "mosssoft_w" (ByVal lpstring1 As String, _ Public Declare Function RatcliffSimilar Lib "mosssoft_w" (ByVal lpstring1 As String, _ Diese Funktionsdeklarationen sind in den Kopf eines VBA-Moduls zu setzen, damit die DLL über sie angesprochen werden kann. Bei der ersten Funktion handelt es sich um einen völlig eigenständig entwickelten Algorithmus, die restlichen drei sind aus der Delphi-Unit HYPERSTRING der inzwischen verschollenen mind spring corp. entliehen. Alle vier Funktionen erwarten zwei zu vergleichende Strings und geben einen Zahlenwert von 0 bis 100 zurück, der den Grad der Übereinstimmung anzeigt. - Funktion SoundExSimilar: Das ist der bereits angesprochene Algorithmus Soundex. Sie gibt 100 aus, wenn die beiden Soundex-Codes übereinstimmen und 0, wenn dem nicht so ist. - Funktion MetaphoneSimilar: Dies ist ein ähnlicher Algorithmus, wie Soundex, mit dem Unterschied, dass hier nicht nur ein 4-Zeichencode generiert wird, sondern ein in der Länge variabler Stringcode. Auch hier wird nach phonetischen Gesichtspunkten verglichen. Die Funktion eignet sich besser für längere Strings. Rückgabewert ist auch hier entweder 100 oder 0 für Übereinstimmung, also im Prinzip Ja/Nein. - Funktion RatcliffSimilar: Ebenfalls phonetischer Vergleich. Die zurückgegebene Zahl dokumentiert jedoch den Grad der Übereinstimmung. Beim Wert 100 sind die Strings absolut identisch (Groß-/Kleinschreibung!). Bei 0 haben sie hingegen überhaupt nichts miteinander zu tun. Wie die Werte dazwischen zu interpretieren sind, ist in eigenen Versuchen zu ermitteln. Es 2 / 5
hat sich als sinnvoll erwiesen, bei einem Rückgabewert 75 von zwei phonetisch identischen Strings auszugehen. Der Vergleich von MAIER und MAYER etwa gibt 80 zurück. - Funktion AreSimilar: Tut das gleiche wie der Ratcliff-Algorithmus und auch die zurückgegebenen Werte sind vergleichbar. Der Unterschied ist jedoch, dass diese Funktion Teilstrings besonders berücksichtigt und höher bewertet. Während Ratcliff zum Beispiel bei den Begriffen " Verkehr" und "Straßenve rkehr " nur eine Übereinstimmung von etwa 57 anzeigt, weil die Begriffe unterschiedlich lang sind, gibt AreSimilar hier 80 zurück, da der Teilstring " Verkehr " vollständig im anderen enthalten ist. Diese Funktion ist also zu bevorzugen, wenn Teilstrings bei der Suche wichtig sind. Ausführungsgeschwindigkeit Als Test dienten mehrere Tausend Vergleichs-Strings der durchschnittlichen Länge 16. Auf einem halbwegs aktuellen Rechner ergab sich pro Sekunde folgende Anzahl von Funktionsaufrufen: Soundex: 196000 AreSimilar: 155000 Ratcliff: 117000 Metaphone: 105000 Das bedeutet, dass eine Abfrage, die etwa die Funktion Soundex implementiert, in einer Sekunde etwa 150000 Datensätze auf Ähnlichkeit vergleichen kann. Beispiel für den Einsatz der Funktionen in Abfragen In Abfragen können API-Funktionen nicht direkt verwendet werden. Es sind in einem Modul stattdessen Wrapper-Funktionen zueinzusetzen, die ihrerseits die API-Routinen aufrufen: Public Function Ratcliff (str1 As String, str2 As String) As Long Ratcliff = RatcliffSimilar (str1, str2) End Function Gegeben sei die Tabelle "Adressen" mit dem Feld "Nachname". Folgende Abfrage gibt dann alle Datensätze mit jenen Namen zurück, die ähnlich wie der anzugebende Parameter [Ähnlicher Name?] sind: SELECT * FROM Adressen WHERE Ratcliff([Ähnlicher Name?], [Nachname]) > 60;Update 03/2009 3 / 5
Seit dem Erscheinen dieser Seite im Jahr 2003 hat sich einiges getan. Inzwischen gibt es zwei neue DLLs, die möglicherweise den Umgang mit den Funktionen erleichtern. Bei beiden handelt es sich um ActiveX-DLLs, die somit keine API-Deklarationen mehr erfordern und einfach in die Verweise eines VBA-Projekts aufgenommen werden können. Die DLLs können dazu an einem beliebigen Ort gespeichert werden - vorzugsweise das Anwendungsverzeichnis - und müssen vor Verwendung im System registriert werden, was über die Windows-Befehlszeile oder den Ausführen-Dialog geschehen kann: regsvr32 <Pfad>dll... also etwa: regsvr32 c:windowssystem32dbstrings.dll - dbstrings.dll Eigenbau unter Delphi. Der Algorithmus ist identisch, wie die oben erwähnte Ratcliff-Methode. Die Bibliothek, die in die Verweise des VBA-Projekts aufgenommen werden muss, lautet hier mosssoft dbstrings Library. Für die einzige darin enthaltene Funktion RatcliffSimilar gilt allerdings das bereits oben Gesagte: Der Einsatz in einer Abfrage erfordert eine VBA- Wrapper-Funktion. - SRatcliff.dll Das ist eine unter VB6 auf Basis eines Quelltexts von Olaf Schmidt entwickelte ActiveX-DLL, die auch noch im Quelltext verfügbar ist (siehe Downloads) - Dank an Olaf! Die Verweisbibliothek lautet hier "Ratcliff Implementation (O. Schmidt)". Auch in dieser Bibliothek wird ein Ratcliff-Algorithmus verwendet, die Vergleichswörter jedoch zuvor durch eine Präprozessor-Routine gejagt, der die Worte auf Umlaute etc. untersucht und optimiert - mit besonderer Berücksichtigung deutscher Sprachgegebenheiten. Der Funktionsaufruf lautet RatcliffSchmidtX mit den beiden Vergleichswörtern als Parametern. Übrigens kann die im Sourcecode-Download enthaltene Klasse Schmidt_Ratcliff.cls auch direkt in ein Access-VBA-Projekt importiert werden, so dass auf eine externe DLL verzichtet werden kann. Die Programmierung dieser DLL ist ansich ziemlich sophisticated und sie arbeitet außerordentlich schnell. Das relativiert sich allerdings, wenn die Klasse direkt in VBA eingesetzt wird. Hier sinkt die Performance auf etwa ein Fünftel im Vergleich zur DLL-Lösung! Wie oft gilt hier die Abwägung: Nimmt man eine Zusatzkomponente in Kauf und benötigt die höhere Performance, oder möchte man sich lieber der Umstände entledigen, die eine COM-DLL mit sich bringt? Immerhin muss diese ja unter Administratorrechten registriert werden... Eine Alternative allerdings gibt es noch: Mit der Zusatz-DLL DirectCOM - ebenfalls von Olaf Schmid ( hier ) - lässt sich die Notwendigkeit der Registrierung von ActiveX-Komponenten umgehen. Über API-Funktionen der DLL können beliebige Objekte anderer DLLs instanziert werden. Wie man das realisieren kann, ist in der neuen Demo (Download unten) beispielhaft zu sehen. Die beiden neuen DLLs kommen in dieser Demo zum Einsatz. Hier kann die Qualität der beiden Ähnlichkeits-Methoden direkt verglichen werden - jede hat ihre Vor- und Nachteile. Spielen Sie einfach mit ein paar Testnamen herum. 4 / 5
Sascha Trowitzsch 03/2009 Downloads mosssoft_w.dll dbstrings.dll (neu ) SRatcliff.DLL (neu ) VB6-Source der SRatcliff.DLL (neu) Ursprüngliche Demo-MDB (Access 2000 ff.) Neue Demo-MDB (Access 2000 ff.) (neu) 5 / 5