# Django 5.2.9 ドキュメント

# 検索

ウェブアプリケーションの一般的なタスクは、ユーザーからの入力を用いてデータベース内のデータを検索することです。簡単なケースなら、オブジェクトのリストをカテゴリごとにフィルタリングすることで実現できるかもしれません。しかし、もっと複雑なユースケースでは、重み付き検索、カテゴリー分け、ハイライト、複数言語対応などが必要になることもあります。このドキュメントでは、そのようなユースケースについて説明するとともに、利用できるツールを紹介します。

ここでは クエリを作成する で使われたのと同じモデルを使って説明します。

## ユースケース

### 標準的なテキストのクエリ

テキストベースのフィールドには、マッチング処理の選択肢があります。たとえば、次のように著者をルックアップしたいと思うかも知れません:

    >>> Author.objects.filter(name__contains="Terry")
    [<Author: Terry Gilliam>, <Author: Terry Jones>]

これは非常に弱い解決方法です。なぜなら、ユーザーが著者名の正確な部分文字列を知っている必要があるからです。case-insensitive なマッチ (`icontains`) を利用すれば少しはましになりますが、ほとんど違いはありません。

### データベースが持つ高度な比較関数

PostgreSQL を使っている場合、 Django は データベース固有のツールの選択肢 があり、より複雑なクエリオプションが利用できます。他のデータベースでは、プラグインやユーザ定義関数を使うことで、様々なツ ールを選択できます。Django は今のところ、そのようなツールをサポートしていません。PostgreSQL の例をいくつか使って、データベースがどのような機能を持っているかを説明します。

他のデータベースにおける検索

`django.contrib.postgres` が提供するすべての検索ツールは、 カスタムルックアップ や データベース関数 のようなパブリック API を利用して構築されています。データベースによっては、同様のAPIを許可するクエリを構築できるはずです。この方法で実現できない特定のことがあれば、チケットをオープンしてください。

上記の例では、大文字と小文字を区別しないルックアップがの方が使いやすいでしょう。英語以外の名前を扱う場合、さらなる改善は `アクセントなし比較` を使うことです:

    >>> Author.objects.filter(name__unaccent__icontains="Helen")
    [<Author: Helen Mirren>, <Author: Helena Bonham Carter>, <Author: Hélène Joy>]

これには別の問題があります。異なる綴りの名前とマッチする場合です。 `Helen` を検索すると `Helena` や `Hélène` がヒットしますが、その逆はヒットしません。もう一つの方法は `trigram_similar` 比較を使うことです。

例えば次のようにします:

    >>> Author.objects.filter(name__unaccent__lower__trigram_similar="Hélène")
    [<Author: Helen Mirren>, <Author: Hélène Joy>]

今度は別の問題です。"Helena Bonham Carter "という長い名前は、もっと長いので表示されません。trigram 検索では、3文字のすべての組み合わせを考慮し、検索文字列とソース文字列の両方で何回現れるかを比較します。より長い名前では、ソース文字列に現れない組み合わせが多くなるため、近接一致とは見なされなくなります。

ここでの比較関数の正しい選択は、使用されている言語や検索されるテキストのタイプなど、データセットによって異なります。これまで見てきた例はすべて、ユーザーがソースデータに近いものを（さまざまな定義で）入力する可能性が高い短い文字列に関するものです。

### 文書ベースの検索

標準的なデータベース操作は、大きなテキストブロックを考慮し始めると、有用なアプローチではなくなります。上記の例は文字列に対する操作と考えることができますが、全文検索は実際の単語を調べます。使用するシステムにもよりますが、以下のような考え方が使われるでしょう:

- "a", "the", "and "などの "ストップワード" は無視する。

- "pony" と "ponies" が似ているとみなされるように、単語のステミング（Stemming）を行う。

- テキスト内での出現頻度や、タイトルやキーワードのようなフィールドの重要性に基づいて単語に重みを付けるなど、異なる基準に基づいて単語を重み付けする。

検索ソフトウェアを使用するための代替手段は数多くありますが、その中でも最も有名なものに Elastic と Solr があります。これらは完全なドキュメントベースの検索ソリューションです。Django モデルからのデータでこれらを使うには、データベース ID への後方参照を含め、データをテキスト文書に変換するレイヤが必要です。このエンジンを使って検索すると、特定の文書が返され、それをデータベースで調べることができます。このプロセスを支援するために設計された、さまざまなサードパーティライブラリがあります。

#### PostgreSQL のサポート

PostgreSQLには独自の全文検索実装が組み込まれています。他の検索エンジンほど強力ではありませんが、データベース内にあるため、カテゴリ分類などの他のリレーショナルクエリと簡単に組み合わせることができるという利点があります。

`django.contrib.postgres` モジュールは、これらのクエリを作成するためのヘルパーをいくつか提供しています。例えば、"cheese" に言及している全てのブログエントリを選択するクエリがあります:

    >>> Entry.objects.filter(body_text__search="cheese")
    [<Entry: Cheese on Toast recipes>, <Entry: Pizza recipes>]

また、フィールドの組み合わせやリレーション先モデルでフィルタをかけることもできます:

    >>> Entry.objects.annotate(
    ...     search=SearchVector("blog__tagline", "body_text"),
    ... ).filter(search="cheese")
    [
        <Entry: Cheese on Toast recipes>,
        <Entry: Pizza Recipes>,
        <Entry: Dairy farming in Argentina>,
    ]

詳細は `contrib.postgres` 全文検索 ドキュメントを参照してください。