Projektbericht zur Nutzung der Solr/Lucene- Suchengine in

Werbung
Projektbericht zur Nutzung der Solr/LuceneSuchengine in einem Zahlungskontrollsystem
Michael Meyer
Joh. Berenberg, Gossler & Co. KG
Hamburg
Schlüsselworte:
Entwicklung, Solr, Lucene, Elastic, Oracle Text, Performance, PL/SQL, SQL, XML
Einleitung:
Zur Erkennung von Geldwäscheverdachtsfällen und Embargoverstößen durchsuchen Banken
Zahlungsvorgänge nach Schlüsselwörtern. Im Rahmen des vorgestellten Projektes wurde diese
Textsuche von Oracle Text auf Solr/Lucene umgestellt. Dargestellt der gesamte Projektablauf:
Motivation für das Projekt; Toolauswahl mit jeweiligen Vor- und Nachteilen; Umsetzung;
Resümee; weitere Anwendungsszenarien. Schwerpunkt ist die Darstellung der Fähigkeiten der
Solr/Lucene-Suchengine.
Ausgangslage, Status-Quo
Im Jahr 2006 wurde die Vorgängerversion einer Suchengine zur Erkennung von
Geldwäscheverdachtsfällen und Embargoverstößen produktiv geschaltet (realisiert mit Oracle
Text). Diese wurde mit den Jahren den steigenden Anforderungen nicht mehr gerecht.
Insbesondere bestand der Wunsch nach unscharfen Suchverfahren und es sollten wesentlich mehr
Datenquellen in die Suche einbezogen werden.
(neue) Anforderungen
• Unscharfe Suchen (fuzzy logic)
• Beispiele:
„Sergey“, „Sergei“, „Sergej“
„Osama“, „Usama“
• Nachvollziehbare Scoringwerte, (Zur Beantwortung der Frage: „warum ist dieser
Vorgang auffällig?“)
• Datenlieferung der Schlüsselbegriffe durch externen Dienstleister. Täglicher Import
• Wesentlich mehr Datenquellen für die Schlüsselbegriffe, wesentlich mehr Schlüsselbegriffe
• Möglichkeit für den Fachbereich, eigene Schlüsselbegriffe zu ergänzen
• „Google“-artige Recherchemöglichkeit über alle Schlüsselbegriffe für den Fachbereich
• Tägliche Prüfung der Stammdaten gegen alle Schlüsselbegriffe
Toolauswahl
Kandidaten, die untersucht wurden:
• Solr / Lucene
• Elastic / Lucene
• Oracle-Text
Oracle Text
-- CONTEXT-Index anlegen:
-- Basistabelle:
CREATE TABLE ZKS2.WC_ENTITIES
( WC_ENTITIES_ID NUMBER(12,0) NOT NULL ENABLE,
ENT_ID NUMBER,
NAME VARCHAR2(4000),
SCHLUESSELBEGRIFF_CONTEXT VARCHAR2(4000),
CONSTRAINT XPKWC_ENTITIES PRIMARY KEY (WC_ENTITIES_ID)
);
CREATE INDEX ZKS2.RULE_SCHLUESSEL_CONTEXT ON ZKS2.WC_ENTITIES
(SCHLUESSELBEGRIFF_CONTEXT)
INDEXTYPE IS CTXSYS.CONTEXT
PARAMETERS
('STORAGE
WCO_BASICSTORAGE
LEXER
WCO_PREFERENCES STOPLIST WCO_STOPLIST TRANSACTIONAL SECTION GROUP
WCO_SECTION_GROUP WORDLIST WCO_WORDLIST MEMORY 500M')
PARALLEL 4 ;
-- Die Parameter der CTX-Umgebung:
DECLARE
v_tablespace varchar2(100) := 'ZKS2INDEX' ;
BEGIN
BEGIN
ctx_ddl.drop_preference('WCO_BASICSTORAGE');
EXCEPTION
WHEN OTHERS THEN NULL; END;
ctx_ddl.create_preference
('WCO_BASICSTORAGE'
,'BASIC_STORAGE');
ctx_ddl.set_attribute
('WCO_BASICSTORAGE','I_TABLE_CLAUSE'
,
'tablespace ' || v_tablespace);
ctx_ddl.set_attribute
('WCO_BASICSTORAGE','K_TABLE_CLAUSE'
,
'tablespace ' || v_tablespace);
ctx_ddl.set_attribute
('WCO_BASICSTORAGE','R_TABLE_CLAUSE'
,
'tablespace ' || v_tablespace ||' LOB(DATA) STORE AS (CACHE)');
ctx_ddl.set_attribute
('WCO_BASICSTORAGE','N_TABLE_CLAUSE'
,
'tablespace ' || v_tablespace);
ctx_ddl.set_attribute
('WCO_BASICSTORAGE','I_INDEX_CLAUSE'
,
'tablespace ' || v_tablespace ||' compress 2');
end;
/
BEGIN
BEGIN
ctx_ddl.drop_stoplist('WCO_STOPLIST');
OTHERS THEN NULL; END;
ctx_ddl.create_stoplist('WCO_STOPLIST');
ctx_ddl.add_stopword('WCO_STOPLIST', 'xxxxx');
ctx_ddl.add_stopword('WCO_STOPLIST', 'yyyyy');
END;
/
EXCEPTION
WHEN
--- Test
begin
BEGIN
ctx_ddl.drop_preference('WCO_PREFERENCES');
EXCEPTION
WHEN OTHERS THEN NULL; END;
CTX_DDL.create_preference('WCO_PREFERENCES', 'BASIC_LEXER');
CTX_DDL.set_attribute('WCO_PREFERENCES','ALTERNATE_SPELLING',
'GERMAN');
CTX_DDL.set_attribute('WCO_PREFERENCES','COMPOSITE', 'GERMAN');
CTX_DDL.set_attribute('WCO_PREFERENCES', 'MIXED_CASE', 'NO');
CTX_DDL.set_attribute('WCO_PREFERENCES', 'BASE_LETTER', 'YES');
CTX_DDL.set_attribute('WCO_PREFERENCES', 'PRINTJOINS', '-');
CTX_DDL.set_attribute('WCO_PREFERENCES','INDEX_STEMS',
'GERMAN');
end;
/
BEGIN
BEGIN ctx_ddl.drop_preference('WCO_WORDLIST'); EXCEPTION WHEN
OTHERS THEN NULL; END;
ctx_ddl.create_preference('WCO_WORDLIST', 'BASIC_WORDLIST');
ctx_ddl.set_attribute('WCO_WORDLIST',
'NDATA_ALTERNATE_SPELLING', 'TRUE');
ctx_ddl.set_attribute('WCO_WORDLIST','NDATA_BASE_LETTER',
'TRUE');
ctx_ddl.set_attribute('WCO_WORDLIST','NDATA_JOIN_PARTICLES',
'de:di:la:da:el:del:qi:abd:los:la:dos:do:an:li:yi:yu:van:jon:un:s
ai:ben:al');
end;
/
-- Beispielabfrage:
SELECT *
FROM (SELECT /* FIRST_ROWS(10) */
score(1) score,
t.name
FROM wc_entities t
where
contains(schluesselbegriff_context,
'NDATA(NAME,"OMAR MOHAMMED")',1) > 0
ORDER BY score DESC
) WHERE ROWNUM<=10;
-- Ergebnis:
Score
Name
86
OMAR MOHAMMED
86
OMAR MOHAMMED MULLAH
76
MUHAMMAD OMAR ZADRAN MOHAMMAD OMAR JADRAN
76
JOUMAA MOHAMAD SAID JOMAA MOHAMED SAID
76
ZADRAN MUHAMMAD OMAR JADRAN MOHAMMAD OMAR
71
MOHAMMAD IBRAHIM OMARI IBRAHIM HAQQANI
69
AL AHMARI HAMED MOHAMMED
67
HOMAYOON MOHAMMAD
Score
Name
67
OSMAN MOHAMED
Problem: Was sagen die Scoringwerte 86, 76, … 67 aus?
Solr/Lucene, Elastic/Lucene
Allgemeines:
• Lucene (1999, Doug Cutting), Solr (2004, Yonik Seeley), Elastic ( 2010)
• Top Level Apache Projects (Lucene: 2005, Solr: 2007)
• Solr, Elastic:
o Datatypes: Text, Integer, Double, Date, Time, Spatial
• Structure:
o Collections [=contain Documents (Document = fields & values; A field can occur
multiple times, Documents are immutable (update = delete + insert new version)]
Popularity (http://db-engines.com/en/ranking/search+engine)
Allgemeine Features Solr / Elastic / Lucene:
• REST API
• Faceting („group by“)
• Pivot
• Language Detection During Indexing
• Spell Checking, Stemming
• Suggester (incremental search)
• More Like This
• Pagination of Results
• Query Elevation („sponsored search“, „editorial boosting“)
• Near time Searching
• Highlighting
• Debug
• Synonyms
• Stopwords (index time, query time)
• Unstructured Content (PDF, MS Office, email, instant messages, …)
• Statistics (avg-query-time, number-of-queries, …)
• Data Import Handler
Solr / Lucene : bekannte Anwender
• Instagram: geo-search API
• AOL: channel: Yellow Pages, Music, NFL Sports, AOL Recipes, Real Estate, Autos, Travel,
StyleList
• SourceForge: faceted search across all its projects
• eBay: search German Classified sites (“Kleinanzeigen”)
• Netflix: site search feature
Solr-Sample Request: http://localhost:8983/solr/gsl/browse?q=hamburg
„Problem“: Berechnung / Nachvollziehbarkeit des Score-Wertes
Einflussfaktoren auf den Scoringwert sind die
• Häufigkeit und Stellung der Suchbegriffe im gefundenen Dokument.
• Gesamtanzahl der Dokumente
TF-IDF-Formel
• tf(t in d) = Term Frequency (number of times term t appears in document d)
• idf(t) = Inverse Document Frequency
1
ln
1
number_of_documents
number_of_documentsinwhichtappers
Durch Überschreiben der similarity-Klasse kann das Scoringverhalten beeinflusst werden. Damit
erhält man „erklärbare“ Scoringwerte.
Default-Verhalten:
Verhalten mit angepasster Similarity-Klasse:
Überschriebene Similaity-Klasse zur Anpassung der Scoringwerte
package de.berenberg.zks.lucene.similarity;
import org.apache.lucene.index.FieldInvertState;
import org.apache.lucene.search.similarities.DefaultSimilarity;
/**
* Die angepasste Similarity Klasse für das ZKS
*
* <ul>
* <li><b>tf</b> = term frequency in document = measure of how
often a term appears in the document</li>
* <li><b>idf</b> = inverse document frequency = measure of how
often the term appears across the index</li>
* <li><b>coord</b> = number of terms in the query that were
found in the document</li>
* <li><b>lengthNorm</b> = measure of the importance of a term
according to the total number of terms in the field</li>
* <li><b>queryNorm</b> = normalization factor so that queries
can be compared</li>
* </ul>
*
* @version
$Revision: 81919 $, 2013-09-02 15:25:18
* @author
Maier
*/
public class ZksSimilarity extends DefaultSimilarity {
@Override
public float coord(int overlap, int maxOverlap) {
float coord = 1.0f;
return coord;
}
@Override
public float queryNorm(float sumOfSquaredWeights) {
float queryNorm = 1.0f;
return queryNorm;
}
@Override
public float lengthNorm(FieldInvertState state) {
final int numTerms;
if (discountOverlaps) {
numTerms = state.getLength() - state.getNumOverlap();
} else {
numTerms = state.getLength();
}
final float lengthNorm;
if (numTerms > 0) {
// Falls es Terms gibt, berechnen wird
// trotzdem keine Plus- bzw. Minuspukte
// berücksichtigen aber den Boost-Wert
lengthNorm = state.getBoost();
} else {
// Ganz ohne Terme lifern wir keine Punkte
lengthNorm = 0.0f;
}
return lengthNorm;
}
@Override
public float tf(float freq) {
float tf = 1.0f;
return tf;
}
@Override
public float idf(long docFreq, long numDocs) {
// Wir igorieren Einfluss der Häufigkeit
// in allen Dokumenten
float idf = 1.0f;
return idf;
}
}
Entscheidungsfindung
Als Tool wird Solr / Lucene gewählt
Projektresümee
Pro / Contra
+ Unscharfe Suchen (fuzzy logic)
+ Nachvollziehbare Ergebnisse, Scoring (mit Austausch der Similarity-Klasse)
+ Wesentlich mehr Datenquellen und mehr Schlüsselbegriffe
+ Datenlieferung der Schlüsselbegriffe durch Dienstleister
+ Möglichkeit für den Fachbereich eigene Schlüsselbegriffe zu ergänzen
+ „Google“-artige Recherchemöglichkeit über alle Schlüsselbegriffe für den Fachbereich
+ Tägliche Prüfung der Stammdaten (ca. 15 Min. Laufzeit)
+ Gute Adminoberfläche
-
zusätzliche Infrastruktur (Backup, Recovery, Hochverfügbarkeit)
Einstellung der JBoss-Unterstützung ab Sol 5.xx
Weitere Anwendungsfälle
Kundensuche, Wertpapiersuche
Kontaktadresse:
Michael Meyer
Joh. Berenberg, Gossler & Co. KG
Neuer Jungfernstieg 20
D-20354 Hamburg
Telefon:
Fax:
E-Mail
Internet:
+49 (0) 40-350 60-186
+49 (0) 40-350 60-954
[email protected]
www.berenberg.de
Herunterladen