2013-04-15 3 views
5

Stellen wir uns vor, dass ich diese Seite Titel in meinem Wiki haben (MediaWiki 1.19.4):Wie wird eine Suche nach Groß- und Kleinschreibung in der MediaWiki-Datenbank durchgeführt?

SOMETHIng 
Sómethìng 
SomêthÏng 
SÒmetHínG 

Wenn ein Benutzer something sucht Ich möchte, dass alle vier Seiten als Ergebnis zurückgegeben werden.

das einzige, was im Moment ich denken könnte, ist diese Abfrage (MySQL Percona 5.5.30-30.2):

SELECT page_title 
FROM page 
WHERE page_title LIKE '%something%' COLLATE utf8_general_ci 

die nur SOMETHIng zurückgibt.

ich auf dem richtigen Weg sein muss, weil wenn ich die Suche sóméthíng OR SÓMÉTHÍNG, bekomme ich SOMETHIng als das Ergebnis. Wie kann ich die Abfrage ändern, damit die anderen Ergebnisse wie erwartet angezeigt werden? Die Leistung ist hier nicht kritisch, da die page Tabelle nur ~ 2K Zeilen enthält.

Dies ist die Tabellendefinition mit dem entsprechenden Bits:

CREATE TABLE page (
    (...) 
    page_title VARCHAR(255) NOT NULL DEFAULT '' COLLATE latin1_bin, 
    (...) 
    UNIQUE INDEX name_title (page_namespace, page_title), 
) 

Die Tabellendefinition darf nicht geändert werden, da dies eine Installation von MediaWiki Lagern und AFAIK erwartet von seinem Code in dieses Feld auf diese Weise definiert ist, (dh Unicode als Binärdaten gespeichert).

Antwort

3

Ich fand die perfekte Lösung, keine modyfing oder Erstellen von Tabellen. Es könnte haben Auswirkungen auf die Leistung (Ich habe nicht getestet), aber wie ich in meiner Frage angegeben, es ist eine ~ 2K Zeilen Tabelle, so dass es nicht viel ausmachen sollte.

Die Ursache des Problems ist, dass MediaWiki UTF8-codierten Text in Latin1-codierten Tabellen speichert. Es ist für MediaWiki nicht von Bedeutung, da es sich dessen bewusst ist und es immer die Datenbank mit dem korrekten Zeichensatz abfragt und seine Sache tut, im Wesentlichen mit MySQL als dumb bit container. Dies geschieht, weil die UTF8-Unterstützung in MySQL offensichtlich nicht für ihre Bedürfnisse geeignet ist (siehe Kommentare in MediaWikis DefaultSettings.php, Variable $wgDBmysql5).

Das Problem tritt auf, wenn Sie möchten, dass die Datenbank selbst UTF8-fähige Operationen ausführen kann (wie ich es in meiner Frage tun wollte). Sie werden das nicht können, weil so weit wie MySQL weiß, speichert es nicht UTF8-codierten Text (obwohl es, wie im vorherigen Absatz erläutert).

Es gibt eine offensichtliche Lösung dafür: In UTF8 die gewünschte Spalte umwandeln, so etwas wie CONVERT(col_name USING utf8). Das Problem hier ist, dass MySQL versucht, gefährlich hilfreich zu sein: es denkt, dass col_name latin1-kodierten Text speichert und es übersetzt (nicht kodieren) jedes Byte in seine UTF8 entspricht, und Sie werden mit doppelt codierten UTF8 enden, Das ist offensichtlich falsch.

Wie kann man vermeiden, dass MySQL so nett und hilfreich ist? Nur in BINARY vor Umwandlung in UTF8 umgewandelt! Auf diese Weise wird MySQL nichts übernehmen und genau das tun, was Sie gefragt haben: Dieses Bit in UTF8 zu codieren. Die genaue Syntax lautet CONVERT(CAST(col_name AS BINARY) USING utf8).

Also das ist meine letzte Abfrage jetzt:

SELECT CONVERT(CAST(page_title AS BINARY) USING utf8) 
FROM page 
WHERE 
    CONVERT(CAST(page_title AS BINARY) USING utf8) 
     LIKE '%keyword_here%' 
      COLLATE utf8_spanish_ci 

Nun, wenn ich something oder sôMëthîNG oder jede Variation zu suchen, bekomme ich alle Ergebnisse!

Bitte beachten Sie, dass ich utf8_spanish_ci verwendet, weil ich die Suche will ñ von n zu unterscheiden, aber nicht á von a. Verwenden Sie eine andere Sortierung gemäß Ihrem Anwendungsfall (here is a complete list).

Weiterführende Links:

+1

, danke für das Teilen. Ich weiß, Leistung ist in Ihrem Fall nicht entscheidend, aber es wäre interessant zu wissen, welche Auswirkungen es hat. – agim

+1

@agim: Bei einer Abfrage wie "% keyword%" sollte es keinen großen Unterschied geben, da MySQL ohnehin einen Table Scan (oder zumindest einen Index Scan) durchführen muss. Eine Abfrage wie "Präfix%" sollte jedoch viel schneller sein, wenn die Spalte richtig sortiert wurde. –

1

Groß- und Kleinschreibung: Sie können einfach die Datenbank für Sie die Arbeit machen lassen

Akzente (Sie bereits mit _ci tun): Um alle Akzente zu haben oder zumindest alle bekannten Akzente Sie könnten zwei Zeilen in Ihrer Datenbank verwenden. Die erste Zeile speichert das Ergebnis so wie es ist (es speichert SomêthÏng) und Sie erstellen zusätzlich eine zweite search_row, die in diesem Fall die Zeichenfolge etwas (ohne Akzente) enthalten würde. Für die Konvertierung können Sie eine Funktion mit Ersetzungsregeln erstellen.

Jetzt können Sie die Suchzeichenfolge mithilfe der Konvertierungsfunktion konvertieren.

Der letzte Schritt ist, machen Sie einen Trigger, der füllt/aktualisiert das Feld search_row jedes Mal, wenn den Titel in der Tabelle Seite einfügen/aktualisieren.

Diese Lösung hätte auch keinen negativen Einfluss auf die Performance!

+0

scheint ein wenig verworren, aber völlig in Ordnung, denke ich.Aber im Idealfall möchte ich vermeiden, die Datenbank zu ändern, wenn es überhaupt möglich ist, es ist eine Bestandsinstallation und sollte so bleiben, um Wartungsprobleme zu vermeiden. –

+0

Ich schlug diese Lösung vor, da sie sprachunabhängig ist. Wenn Sie nur eine Sprache verwenden, dann ist hier eine Lösung für deutsche Umlaute: http://stackoverflow.com/questions/2722044/mysql-german-accents-not-sensitive-search-in-full-text-searches Soweit ich weiß, wird die Verwendung von Akzenten aus verschiedenen Sprachen immer zu Problemen führen – agim

3

Das MediaWiki TitleKey extension ist grundsätzlich dafür gedacht, aber es funktioniert nur fallend. wenn Sie es ein bisschen Hacking nicht jedoch nichts, und haben die PHP iconv extension installiert haben, können Sie TitleKey_body.php bearbeiten und ersetzen Sie die Methode:

static function normalize($text) { 
    global $wgContLang; 
    return $wgContLang->caseFold($text); 
} 

mit zB:

static function normalize($text) { 
    return strtoupper(iconv('UTF-8', 'US-ASCII//TRANSLIT', $text)); 
} 

und (re) Führen Sie rebuildTitleKeys.php aus.Die TitleKey-Erweiterung speichert ihre normalisierten Titel in einer separate table, überraschend titlekey genannt. Es ist beabsichtigt, über die MediaWiki-Suchoberfläche zuzugreifen, aber wenn Sie möchten, können Sie sicherlich auch direkt abfragen, z. wie folgt:

SELECT page.* FROM page 
    JOIN titlekey ON tk_page = page_id 
WHERE tk_namespace = 0 AND tk_key = 'SOMETHING'; 
Verwandte Themen