Text Analytics Referat: Improving Suffix Array Locality for Fast Pattern Matching on Disk Nils Alberti & Jürgen Eicher, 12. Juni 2008
Einführung Stringmatching bisher: Analyse des Patterns zum schnellen Auffinden in einem unbekannten Text (Boyer- Moore, Keyword- Tree)
Einführung Stringmatching bisher: Analyse des Patterns zum schnellen Auffinden in einem unbekannten Text (Boyer- Moore, Keyword- Tree) Jetzt: Aufbereiten des Textes um zukünftige Pattern schnell zu finden (das Google- Problem)
Suffixrepräsentation Definition: Ein Suffix S i eines Strings der Länge n ist der Substring, der an Stelle i beginnt und an Stelle n endet. Ein String der Länge n hat also n Suffixe. Jeder Substring ist also auch Präfix eines Suffixes!
Suffixrepräsentation Text: suhrkamp Pattern: uhr suhrkamp suhrkamp suhrkamp suhrkamp suhrkamp suhrkamp suhrkamp suhrkamp
Suffixtree Versuch alle Suffixe kompakt zu repräsentieren: Idee: Alle Suffixe mit dem gleichen Präfix liegen im selben Teilbaum.
Suffixtree Definition: Für einen Suffixtree T für einen String S gilt: T hat eine Wurzel und n Blätter: Jedes Suffix ist durch genau ein Blatt repräsentiert.
Suffixtree Definition: Für einen Suffixtree T für einen String S gilt: T hat eine Wurzel und n Blätter: Jedes Suffix ist durch genau ein Blatt repräsentiert. Jedes Blatt ist mit dem Index dieses Suffix gelabelt
Suffixtree Definition: Für einen Suffixtree T für einen String S gilt: T hat eine Wurzel und n Blätter: Jedes Suffix ist durch genau ein Blatt repräsentiert. Jedes Blatt ist mit dem Index dieses Suffix gelabelt Jede Kante ist mit einem Substring von S gelabelt
Suffixtree Definition: Für einen Suffixtree T für einen String S gilt: T hat eine Wurzel und n Blätter: Jedes Suffix ist durch genau ein Blatt repräsentiert. Jedes Blatt ist mit dem Index dieses Suffix gelabelt Jede Kante ist mit einem Substring von S gelabelt Alle Label von Kanten, die vom selben Knoten ausgehen beginnen mit unterschiedlichen Zeichen
Suffixtree Definition: Für einen Suffixtree T für einen String S gilt: T hat eine Wurzel und n Blätter: Jedes Suffix ist durch genau ein Blatt repräsentiert. Jedes Blatt ist mit dem Index dieses Suffix gelabelt Jede Kante ist mit einem Substring von S gelabelt Alle Label von Kanten, die vom selben Knoten ausgehen beginnen mit unterschiedlichen Zeichen Jeder innere Knoten hat mindestens zwei Kinder
Suffixtree Definition: Für einen Suffixtree T für einen String S gilt: T hat eine Wurzel und n Blätter: Jedes Suffix ist durch genau ein Blatt repräsentiert. Jedes Blatt ist mit dem Index dieses Suffix gelabelt Jede Kante ist mit einem Substring von S gelabelt Alle Label von Kanten, die vom selben Knoten ausgehen beginnen mit unterschiedlichen Zeichen Jeder innere Knoten hat mindestens zwei Kinder Ein Pfad von der Wurzel zu einem Blatt mit Label i entspricht dem Suffix S[i...n]
Suffixtree... T hat eine Wurzel und n Blätter: Jedes Suffix ist durch genau ein Blatt repräsentiert.... was ist, wenn ein Suffix Präfix eines anderen ist?
Suffixtree... T hat eine Wurzel und n Blätter: Jedes Suffix ist durch genau ein Blatt repräsentiert.... was ist, wenn ein Suffix Präfix eines anderen ist? es endet irgendwo auf dem Pfad! damit wäre es kein Suffixtree mehr!
Suffixtree... T hat eine Wurzel und n Blätter: Jedes Suffix ist durch genau ein Blatt repräsentiert.... was ist, wenn ein Suffix Präfix eines anderen ist? es endet irgendwo auf dem Pfad! damit wäre es kein Suffixtree mehr! Lösung: Jedes Suffix auf ein nicht im Text vorkommendes Zeichen enden lassen.
Beispiel: aa -> aa$ Suffixtree aa aa$ a a$
MISSISSIPPI$ Suffixtree - Beispiel
MISSISSIPPI$ Suffixtree - Beispiel
MISSISSIPPI$ Suffixtree - Beispiel
MISSISSIPPI$ Suffixtree - Beispiel
MISSISSIPPI$ Suffixtree - Beispiel
MISSISSIPPI$ Suffixtree - Beispiel
MISSISSIPPI$ Suffixtree - Beispiel
MISSISSIPPI$ Suffixtree - Beispiel
MISSISSIPPI$ Suffixtree - Beispiel
MISSISSIPPI$ Suffixtree - Beispiel
MISSISSIPPI$ Suffixtree - Beispiel
MISSISSIPPI$ Suffixtree - Beispiel
MISSISSIPPI$ Suffixtree - Beispiel
MISSISSIPPI$ Suffixtree - Beispiel
MISSISSIPPI$ Suffixtree - Beispiel
MISSISSIPPI$ Suffixtree - Beispiel
MISSISSIPPI$ Suffixtree - Beispiel
MISSISSIPPI$ Suffixtree - Beispiel
MISSISSIPPI$ Suffixtree - Beispiel
MISSISSIPPI$ Suffixtree - Beispiel
MISSISSIPPI$ Suffixtree - Beispiel
MISSISSIPPI$ Suffixtree - Beispiel
MISSISSIPPI$ Suffixtree - Beispiel
MISSISSIPPI$ Suffixtree - Beispiel
MISSISSIPPI$ Suffixtree - Beispiel es fehlen noch die Label der Blätter!
MISSISSIPPI$ Suffixtree - Beispiel
Suffixtree - Suche Wie lange dauert jetzt die Suche?
Suffixtree - Suche Wie lange dauert jetzt die Suche? O( Pattern )?
Suffixtree - Suche Wie lange dauert jetzt die Suche? O( Pattern )? Fast! Wir müssen aber alle Vorkommen des Pattern finden. Dafür müssen wir alle Blätter im Unterbaum finden. Also O( Pattern + #Vorkommen)
Suffixtree - Problem Wir brauchen sehr viel Platz für die Baumstruktur(Pointer,...).
Suffixtree - Problem Wir brauchen sehr viel Platz für die Baumstruktur(Pointer,...). Gesucht ist eine Datenstruktur, die den Speicherbedarf des Strings nicht (wesentlich) vergrößert.
Suffixtree - Problem Wir brauchen sehr viel Platz für die Baumstruktur(Pointer,...). Gesucht ist eine Datenstruktur, die den Speicherbedarf des Strings nicht (wesentlich) vergrößert. Lösung: Suffixarray
Suffixarray Definition: Ein Suffixarray A für String S ist ein Integerarray der Länge S. A[i] gibt die Startposition in S des Suffix an, das nach lexikographischer Sortierung an Stelle i steht.
Suffixarray Definition: Ein Suffixarray A für String S ist ein Integerarray der Länge S. A[i] gibt die Startposition in S des Suffix an, das nach lexikographischer Sortierung an Stelle i steht. 1. Sortiere alle Suffixe lexikographisch 2. Liste und Suffixarray parallel durchlaufen 3. Zum i-ten Listeneintrag wird A[i] der Stringindex des Suffixes zugewiesen
Suffixarray - Beispiel Suffixe: bauzaun lexikograph. Sortierung aun auzaun bauzaun n un uzaun zaun Suffixarray A[1] = 5 A[2] = 2 A[3] = 1 A[4] = 7 A[5] = 6 A[6] = 3 A[7] = 4
Suffixarray - Beispiel Suffixe: bauzaun lexikograph. Sortierung aun auzaun bauzaun n un uzaun zaun Suffixarray A[1] = 5 A[2] = 2 A[3] = 1 A[4] = 7 A[5] = 6 A[6] = 3 A[7] = 4
Suffixarray - Beispiel bauzaun aun auzaun bauzaun n un uzaun zaun A[1] = 5 A[2] = 2 A[3] = 1 A[4] = 7 A[5] = 6 A[6] = 3 A[7] = 4 Wie suchen wir jetzt ein Pattern?
Suffixarray - Beispiel bauzaun aun auzaun bauzaun n un uzaun zaun A[1] = 5 A[2] = 2 A[3] = 1 A[4] = 7 A[5] = 6 A[6] = 3 A[7] = 4 Wie suchen wir jetzt ein Pattern? Binäre Suche!
Suffixarray - Beispiel Wir suchen jetzt un in bauzaun: bauzaun aun auzaun bauzaun n un uzaun zaun A[1] = 5 A[2] = 2 A[3] = 1 A[4] = 7 A[5] = 6 A[6] = 3 A[7] = 4
Suffixarray - Beispiel Wir suchen jetzt un in bauzaun: bauzaun aun auzaun bauzaun n un uzaun zaun A[1] = 5 A[2] = 2 A[3] = 1 A[4] = 7 A[5] = 6 A[6] = 3 A[7] = 4
Suffixarray - Beispiel Wir suchen jetzt un in bauzaun: bauzaun aun auzaun bauzaun n un uzaun zaun A[1] = 5 A[2] = 2 A[3] = 1 A[4] = 7 A[5] = 6 A[6] = 3 A[7] = 4
Suffixarray - Beispiel Wir suchen jetzt un in bauzaun: bauzaun aun auzaun bauzaun n un uzaun zaun A[1] = 5 A[2] = 2 A[3] = 1 A[4] = 7 A[5] = 6 A[6] = 3 A[7] = 4 n < lex un
Suffixarray - Beispiel Wir suchen jetzt un in bauzaun: bauzaun aun auzaun bauzaun n un uzaun zaun A[1] = 5 A[2] = 2 A[3] = 1 A[4] = 7 A[5] = 6 A[6] = 3 A[7] = 4 n < lex un
Suffixarray - Beispiel Wir suchen jetzt un in bauzaun: bauzaun aun auzaun bauzaun n un uzaun zaun A[1] = 5 A[2] = 2 A[3] = 1 A[4] = 7 A[5] = 6 A[6] = 3 A[7] = 4 un = lex un
Suffixarray - Erweiterung Überlegung: Suffixarray sehr groß und generiert aus kleinem Alphabet(z.B. ASCII) Dann haben Suffixe häufig lange identische Präfixe Beispiel: menschliche Genom
Suffixarray - Erweiterung Idee: zusätzliches Array gleicher Länge, das an Stelle j die Länge des gemeinsamen Präfix von SA[j] und SA[j-1] speichert.
Suffixarray - Erweiterung Beispiel: bauzaun aun auzaun bauzaun n un uzaun zaun A[1] = 5 A[2] = 2 A[3] = 1 A[4] = 7 A[5] = 6 A[6] = 3 A[7] = 4 LCP[1] = LCP[2] = 2 LCP[3] = 0 LCP[4] = 0 LCP[5] = 0 LCP[6] = 1 LCP[7] = 0
Suffixarray - Erweiterung LCP kann auch allgemeiner definiert werden, nicht nur für lexikographisch nebeneinanderstehende Suffixe: Definition: lcp(y,z) ist das längste gemeinsame Präfix zweier Strings y und z
Suffixarray - Erweiterung Quelle: Gabriele Koller http://www.ads.tuwien.ac.at/teaching/ws04/effalg/stringsuche-beispiele.pdf
Suffixarray - Problem Wir haben selten genug Hauptspeicher -> Suffixarray liegt auf der Festplatte
Suffixarray - Problem Wir haben selten genug Hauptspeicher -> Suffixarray liegt auf der Festplatte wir greifen also O(log(n)) Mal bei einer binären Suche an verschiedenen Stellen auf die Festplatte zu
Suffixarray - Problem Wir haben selten genug Hauptspeicher -> Suffixarray liegt auf der Festplatte wir greifen also O(log(n)) Mal bei einer binären Suche an verschiedenen Stellen auf die Festplatte zu Ziel: Festplattenzugriffe so wenig wie möglich und wenn dann sequentielles Lesen
Suffixarray - Problem Wir haben selten genug Hauptspeicher -> Suffixarray liegt auf der Festplatte wir greifen also O(log(n)) Mal bei einer binären Suche an verschiedenen Stellen auf die Festplatte zu Ziel: Festplattenzugriffe so wenig wie möglich und wenn dann sequentielles Lesen
LOF-SA Datenstruktur Idee: kleinen Baum über das Array legen, dadurch Partition des Arrays Ein Pfad des Baumes wird traversiert und dann ein kleiner Bereich des Arrays auf der Festplatte gelesen.
LOF-Trie Trie versus Tree: Im Trie besteht das Label jeder Kante aus nur einem Zeichen.
LOF-Trie LOF-Trie: Variante des Suffix-Trie
LOF-Trie LOF-Trie: Variante des Suffix-Trie Jeder Knoten hat start- und end- Werte für den Bereich des Arrays, den er abdeckt.
LOF-Trie LOF-Trie: Variante des Suffix-Trie Jeder Knoten hat start- und end- Werte für den Bereich des Arrays, den er abdeckt. Es gibt einen bucket threshold b, wodurch die Größe des Baumes, bzw. dieser der Buckets gesteuert wird.
LOF-Trie LOF-Trie: Variante des Suffix-Trie Jeder Knoten hat start- und end- Werte für den Bereich des Arrays, den er abdeckt. Es gibt einen bucket threshold b, wodurch die Größe des Baumes, bzw. dieser der Buckets gesteuert wird. Der Baum wird ab einem Knoten v gepruned, für den gilt: occ(v)<= b < occ(parent(b))
LOF-Trie Jedes Blatt v verweist also auf einen Bucket der Größe höchstens b.
LOF-Trie Jedes Blatt v verweist also auf einen Bucket der Größe höchstens b. Sämtliche durch die Einträge des SA-Buckets induzierten Suffixe haben einen gemeinsames Präfix der Baumtiefe entsprechend.
LOF-Trie
Das LOF-Array - Tripel <LCP[i], SA[i], F[0 f-1]> SA[i] ist Anfangspos. des i-ten Suffix (lexikographische Sortierung) von T LCP[i] ist längster gemeinsamer Präfix von T[SA[i-1] n] und T[SA[i] n] F[0 f-1] ( fringe ) sind f Zeichen im Template nach dem LCP - Großes f reduziert (Festplatten-) Zugriffe auf T - Aber: b LOF-Array-Einträge pro Block
Das LOF-Array
Pattern-Matching - Zunächst: Präfix matchen im LOF-Trie Dieser ist so konstruiert, dass er komplett in den Arbeitsspeicher passt. - Falls nur Mismatches: fertig, kein Fund - Falls Pattern vollständig im Trie liegt: Letzter erreichter Knoten kennt Start und Ende des matchenden Intervalls im LOF-Array - Sonst: Match nur möglich im Intervall des LOF-Arrays zwischen Start und Ende des erreichten Terminals
SearchLOFArray(blockstart, blockend, P,match, m) 1: curr blockstart 2: match the length of the common prefix for this LOF bucket 3: while match m do 4: if LA[curr].L < match or curr = blockend then If the first condition, then already past location of longest match, without finding a match of m, and if the second condition, LOF block is exhausted. Either way, 5: return No match Otherwise, increase match length if appropriate. 6: match MatchEntryToPattern(match m, curr) 7: curr curr + 1 Scan through LCP values counting occurrences. 8: start curr - 1 9: while curr blockend and match LA[curr].L do 10: curr curr + 1 11: return (start, curr - 1)
MatchEntryToPattern(match m, curr) 1: if f = 0 or LA[curr].L + f < match then Either there are no fringe characters or it is known that P matches all of them, so go straight to the text. 2: p compare(p[match...m-1], T [LA[curr].O + match...n]) 3: match match + p 4: else Check the pattern against the fringe characters. 5: p compare(p[match m-1], LA[curr].F [0...f-1]) 6: match match + p 7: if match = LA[curr].L + f then The pattern matches all the fringe characters, check x. 8: p compare(p[match m-1], T[LA[curr].O + match n]) 9: match match + p 10: return match
Laufzeit-Vergleich Vergleichssysteme: - TDD: disk-basierte Suffix-Tree-Implementation - TRELLIS: disk-basierte Suffix-Tree-Implementation, schnell aber speicherintensiv, Template komprimiert im Hauptspeicher, nur DNA - Suffix-Array, disk-basiert - Suffix-Array mit zusätzlichem kleinem Index (SPAT) Qualität der verwendeten Vergleichssysteme lässt sich nicht beurteilen.
Laufzeit-Vergleich Testdaten: - 8 verschiedene Human-DNA-Präfixe, 10M-2000M Basen - 233MB Genbank nicht-redundante Proteine - Wall Street Journal TREC corpus subcollection Sonderzeichen entfernt, Leerzeichen in Z umgewandelt - Je 1000 zufällig gewählte Template-Sequenzen unterschiedlicher Länge
Laufzeit-Vergleich Parameter-Wahl: - kleines b beschleunigt sequentielle Suche in Buckets - großes b verkleinert LOF-Trie, bis er in Hauptspeicher passt - kleines f verkleinert das LOF-Array - großes f reduziert Zugriff auf Template - Gewählt: b = 4096, f = 4
Laufzeit-Vergleich
Laufzeit-Vergleich