5

私のウィキ (MediaWiki 1.19.4) にこれらのページ タイトルがあるとしましょう:

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

ユーザーが検索した場合、something4 ページすべてが結果として返されるようにしたいと考えています。

現時点で考えられるのは、次のクエリ (MySQL Percona 5.5.30-30.2) だけです。

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

を返すだけSOMETHIngです。

ORを検索すると結果が得sóméthíngSÓMÉTHÍNGSOMETHIngられるため、正しい道を進んでいる必要がありますクエリを変更して、他の結果を期待どおりに取得するにはどうすればよいですか? pageテーブルには最大 2,000 行しか含まれていないため、ここではパフォーマンスは重要ではありません。

これは、関連するビットを含むテーブル定義です。

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

これはMediaWikiのストックインストールであり、そのコードはこのフィールドがそのように定義されていることを期待しているため(つまり、バイナリデータとして格納されたユニコード)、テーブル定義を変更してはなりません。

4

3 に答える 3

3

MediaWiki のTitleKey 拡張機能は、基本的にこれを目的として設計されていますが、ケース フォールディングのみを行います。ただし、少しハッキングしてもかまわず、PHP のiconv 拡張機能がインストールされている場合は、TitleKey_body.phpを編集してメソッドを置き換えることができます。

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

例:

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

そして、rebuildTitleKeys.php を (再) 実行します。

TitleKey 拡張機能は、正規化されたタイトルを別のテーブルに保存しますtitlekey。MediaWiki の検索インターフェイスからアクセスすることを意図していますが、必要に応じて、次のように直接クエリを実行することもできます。

SELECT page.* FROM page
  JOIN titlekey ON tk_page = page_id
WHERE tk_namespace = 0 AND tk_key = 'SOMETHING';
于 2013-04-15T12:49:24.407 に答える
3

テーブルを変更したり作成したりする必要のない、完璧な解決策を見つけました。パフォーマンスに影響を与える可能性があります (テストはしていません) が、質問で述べたように、これは ~2K 行のテーブルであるため、それほど重要ではありません。

問題の根本は、MediaWiki が UTF8 でエンコードされたテキストを latin1 でエンコードされたテーブルに保存することです。MediaWiki はそれを認識しており、常に正しい文字セットを使用してデータベースにクエリを実行し、基本的にMySQL をダム ビット コンテナーとして使用して処理を実行するため、MediaWiki にとってはそれほど重要ではありません。これは、MySQL での UTF8 サポートがそのニーズに対して明らかに不十分であるためです (MediaWiki のDefaultSettings.php, variableのコメントを参照してください$wgDBmysql5)。

データベース自体がUTF8対応の操作を実行できるようにしたい場合に問題が発生します(私の質問でやりたかったように)。MySQL が知る限り、UTF8 でエンコードされたテキストを格納していないため(前の段落で説明したように格納されています)、それを行うことはできません。

これには明らかな解決策があります。使用する列を UTF8 にキャストします。このようなものCONVERT(col_name USING utf8)です。ここでの問題は、MySQL が危険なほど役立つことを試みていることです。これcol_nameは、latin1 でエンコードされたテキストを格納していると考え、各バイトを同等の UTF8 に変換 (エンコードではなく) し、二重にエンコードされた UTF8 で終了します。違う。

MySQL が非常に便利で使いやすくならないようにするにはどうすればよいでしょうか? UTF8 に変換するに BINARY にキャストするだけです。そうすれば、MySQL は何も仮定せず、要求どおりに正確に実行します: この一連のビットを UTF8 にエンコードします。正確な構文は次のとおりですCONVERT(CAST(col_name AS BINARY) USING utf8)

これが私の最後のクエリです。

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

somethingまたは、またはそのバリエーションを検索するsôMëthîNGと、すべての結果が得られます。

utf8_spanish_ci検索で とは区別ñしたいが、 とは区別したくnないので、私が使用したことに注意してください。ユースケースに応じて異なる照合順序を使用してください (ここに完全なリストがあります)。áa

関連リンク:

于 2013-04-15T15:00:03.570 に答える
1

大文字と小文字を区別しない:データベースに作業を任せることができます (既に_ciを使用しています) 。

アクセント: すべてのアクセント、または少なくともすべての既知のアクセントを取得するには、データベースで 2 つの行を使用できます。最初の行は結果をそのまま格納し (つまり、SomethÏngを格納することを意味します)、さらに 2 番目のsearch_rowを作成します。この場合、この場合、文字列something を(アクセントなしで) 格納します。変換のために、置換ルールを使用して関数を作成できます。

これで、変換関数を使用して検索文字列を変換できます。

最後のステップは、テーブルpageでタイトルを挿入/更新するたびにフィールドsearch_rowを入力/更新するトリガーを作成することです。

このソリューションは、パフォーマンスにも悪影響を及ぼしません。

于 2013-04-15T11:50:32.237 に答える