# Django 6.0.7 ドキュメント

# 全文検索

`django.contrib.postgres.search` モジュールのデータベース関数は PostgreSQL の 全文検索エンジン を利用しやすくしています。

このドキュメントの例では、 クエリを作成する で定義されたモデルを使用します。

参考

検索の概要については、 トピックのドキュメント を参照してください。

## `search` ルックアップ

全文検索の一般的な使用方法は、データベースの1つのカラムに対して1つの用語を検索することです。たとえば:

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

これにより、データベース内の `body_text` フィールドから `to_tsvector` が作成され、検索語 `'Cheese'` から `plainto_tsquery` が作成されます。両方ともデフォルトのデータベース検索設定を使用しています。結果は、クエリとベクトルを一致させることで取得されます。

`search` ルックアップを使用するには、`INSTALLED_APPS` に `'django.contrib.postgres'` を含める必要があります。

## `SearchVector`

class SearchVector(*expressions, config=None, weight=None)

単一のフィールドに対する検索は素晴らしいですが、制約があります。検索対象となる `Entry` インスタンスは `Blog` に属しており、 `tagline` フィールドを持っています。両方のフィールドに対してクエリを行うには、 `SearchVector` を使用します:

    >>> from django.contrib.postgres.search import SearchVector
    >>> Entry.objects.annotate(
    ...     search=SearchVector("body_text", "blog__tagline"),
    ... ).filter(search="Cheese")
    <QuerySet [<Entry: Cheese on Toast recipes>, <Entry: Pizza Recipes>]>

`SearchVector` への引数は、任意の `Expression` またはフィールドの名前を指定できます。複数の引数は、スペースを使用して連結され、検索ドキュメントにすべて含まれます。

`SearchVector` オブジェクトは組み合わせて再利用できます。たとえば:

    >>> Entry.objects.annotate(
    ...     search=SearchVector("body_text") + SearchVector("blog__tagline"),
    ... ).filter(search="Cheese")
    <QuerySet [<Entry: Cheese on Toast recipes>, <Entry: Pizza Recipes>]>

`config` パラメータおよび `weight` パラメータの説明については、検索設定を変更する と クエリを重み付けする を参照してください。

## `SearchQuery`

class SearchQuery(value, config=None, search_type='plain')

`SearchQuery` は、ユーザーが提供した用語を検索クエリオブジェクトに変換し、データベースが検索ベクトルと比較する機能を提供します。デフォルトでは、ユーザーが提供したすべての単語がステミングアルゴリズムを通過され、その結果の用語すべてに一致するものを検索します。

もし `search_type` が `'plain'` (デフォルト) の場合、用語は別々のキーワードとして扱われます。もし `search_type` が `'phrase'` の場合、用語は1つのフレーズとして扱われます。もし `search_type` が `'raw'` の場合、用語と演算子を含む書式付きの検索クエリを指定できます。もし `search_type` が `'websearch'` の場合、Web検索エンジンで使用されるものに類似した書式で検索クエリを指定できます。 `'websearch'` には PostgreSQL ≥ 11 が必要です。違いや構文については PostgreSQL の Full Text Search docs を参照してください。例:

    >>> from django.contrib.postgres.search import SearchQuery, Lexeme
    >>> SearchQuery("red tomato")  # two keywords
    >>> SearchQuery("tomato red")  # same results as above
    >>> SearchQuery("red tomato", search_type="phrase")  # a phrase
    >>> SearchQuery("tomato red", search_type="phrase")  # a different phrase
    >>> SearchQuery("'tomato' & ('red' | 'green')", search_type="raw")  # boolean operators
    >>> SearchQuery(
    ...     "'tomato' ('red' OR 'green')", search_type="websearch"
    ... )  # websearch operators
    >>> SearchQuery(Lexeme("tomato") & (Lexeme("red") | Lexeme("green")))  # Lexeme objects

`SearchQuery` の用語は論理的に組み合わせることで、柔軟性を高めることができます:

    >>> from django.contrib.postgres.search import SearchQuery
    >>> SearchQuery("meat") & SearchQuery("cheese")  # AND
    >>> SearchQuery("meat") | SearchQuery("cheese")  # OR
    >>> ~SearchQuery("meat")  # NOT

`config` パラメータの説明については、検索設定を変更する を参照してください。

Changed in Django 6.0:

`Lexeme` オブジェクトが追加されました。

## `SearchRank`

class SearchRank(vector, query, weights=None, normalization=None, cover_density=False)

これまでに、ベクトルとクエリの間で一致する結果を返してきました。おそらく結果をある種の関連性によって並べ替えたいと思うかもしれません。PostgreSQLにはランキング関数が用意されており、クエリ用語がドキュメント内にどれだけ多く現れるか、用語がドキュメント内でどれだけ近くにあるか、そしてそれらが発生するドキュメント内の部分がどれだけ重要かを考慮します。一致度が高いほど、ランクの値が高くなります。関連度で並び替えるには:

    >>> from django.contrib.postgres.search import SearchQuery, SearchRank, SearchVector
    >>> vector = SearchVector("body_text")
    >>> query = SearchQuery("cheese")
    >>> Entry.objects.annotate(rank=SearchRank(vector, query)).order_by("-rank")
    <QuerySet [<Entry: Cheese on Toast recipes>, <Entry: Pizza recipes>]>

`weights` パラメータの説明については、クエリを重み付けする を参照してください。

`cover_density` パラメーターを `True` に設定して、カバー密度ランキングを有効にします。これにより、クエリ用語の一致する近接度が考慮されます。

`normalization` パラメータに整数を指定すると、順位の正規化を制御できます。この整数はビットマスクであり、複数の動作を組み合わせることができます。

    >>> from django.db.models import Value
    >>> Entry.objects.annotate(
    ...     rank=SearchRank(
    ...         vector,
    ...         query,
    ...         normalization=Value(2).bitor(Value(4)),
    ...     )
    ... )

PostgreSQLのドキュメントに、 different rank normalization options についての詳細があります。

## `SearchHeadline`

class SearchHeadline(expression, query, config=None, start_sel=None, stop_sel=None, max_words=None, min_words=None, short_word=None, highlight_all=None, max_fragments=None, fragment_delimiter=None)

単一のテキストフィールドまたは式、クエリ、設定、およびオプションのセットを受け入れ、ハイライトされた検索結果を返します。

`start_sel` パラメータと `stop_sel` パラメータには、ハイライトされたクエリ語をドキュメントで囲むために使用する文字列値を設定します。PostgreSQLのデフォルトは `<b>` と `</b>` です。

パラメータ `max_words` と `min_words` に整数値を指定して、最長と最短の見出しを決定します。PostgreSQLのデフォルトは35と15です。

`short_word` パラメータに整数値を指定すると、各見出しでこの長さ以下の単語を破棄します。PostgreSQLのデフォルトは3です。

`highlight_all` パラメータを `True` に設定すると、フラグメントの代わりにドキュメント全体を使用し、 `max_words`、`min_words`、`short_word` パラメータを無視します。PostgreSQLではデフォルトで無効になっています。

表示するフラグメントの最大数を設定するには、 `max_fragments` に0以外の整数値を指定してください。PostgreSQLではデフォルトで無効になっています。

`fragment_delimiter` 文字列パラメータを設定すると、フラグメント間の区切り文字を構成できます。PostgreSQL のデフォルトは `" ... "` です。

PostgreSQL のドキュメントには、highlighting search results に関する詳細が記載されています。

使用例:

    >>> from django.contrib.postgres.search import SearchHeadline, SearchQuery
    >>> query = SearchQuery("red tomato")
    >>> entry = Entry.objects.annotate(
    ...     headline=SearchHeadline(
    ...         "body_text",
    ...         query,
    ...         start_sel="<span>",
    ...         stop_sel="</span>",
    ...     ),
    ... ).get()
    >>> print(entry.headline)
    Sandwich with <span>tomato</span> and <span>red</span> cheese.

`config` パラメータの説明については、検索設定を変更する を参照してください。

## 検索設定を変更する

`SearchVector` および `SearchQuery` に `config` 属性を指定して、異なる検索設定を使用できます。これにより、データベースで定義された異なる言語の解析機能や辞書を使用できます。

    >>> from django.contrib.postgres.search import SearchQuery, SearchVector
    >>> Entry.objects.annotate(
    ...     search=SearchVector("body_text", config="french"),
    ... ).filter(search=SearchQuery("œuf", config="french"))
    <QuerySet [<Entry: Pain perdu>]>

`config` の値は別の列にも保存できます。

    >>> from django.db.models import F
    >>> Entry.objects.annotate(
    ...     search=SearchVector("body_text", config=F("blog__language")),
    ... ).filter(search=SearchQuery("œuf", config=F("blog__language")))
    <QuerySet [<Entry: Pain perdu>]>

## クエリを重み付けする

すべてのフィールドがクエリにおいて同じ重要度を持つとは限りません。そのため、それらを組み合わせる前に、複数のベクトルの重みを設定できます。

    >>> from django.contrib.postgres.search import SearchQuery, SearchRank, SearchVector
    >>> vector = SearchVector("body_text", weight="A") + SearchVector(
    ...     "blog__tagline", weight="B"
    ... )
    >>> query = SearchQuery("cheese")
    >>> Entry.objects.annotate(rank=SearchRank(vector, query)).filter(rank__gte=0.3).order_by(
    ...     "rank"
    ... )

重みは次のいずれかの文字である必要があります: D, C, B, A。デフォルトでは、これらの重みはそれぞれ `0.1`, `0.2`, `0.4`, `1.0` に対応しています。異なる重みを使用する場合は、同じ順序で四つの浮動小数点数のリストを、上記の通りに `SearchRank` に `weights` として渡してください。

    >>> rank = SearchRank(vector, query, weights=[0.2, 0.4, 0.6, 0.8])
    >>> Entry.objects.annotate(rank=rank).filter(rank__gte=0.3).order_by("-rank")

## `Lexeme`

New in Django 6.0.

class Lexeme(value, output_field=None, *, invert=False, prefix=False, weight=None)

`Lexeme` objects allow search operators to be safely used with strings from an untrusted source. The content of each lexeme is escaped so that any operators that may exist in the string itself will not be interpreted.

You can combine lexemes with other lexemes using the `&` and `|` operators and also negate them with the `~` operator. For example:

    >>> from django.contrib.postgres.search import SearchQuery, SearchVector, Lexeme
    >>> vector = SearchVector("body_text", "blog__tagline")
    >>> Entry.objects.annotate(search=vector).filter(
    ...     search=SearchQuery(Lexeme("fruit") & Lexeme("dessert"))
    ... )
    <QuerySet [<Entry: Apple Crumble Recipes>, <Entry: Banana Split Recipes>]>

    >>> Entry.objects.annotate(search=vector).filter(
    ...     search=SearchQuery(Lexeme("fruit") & Lexeme("dessert") & ~Lexeme("banana"))
    ... )
    <QuerySet [<Entry: Apple Crumble Recipes>]>

Lexeme objects also support term weighting and prefixes:

    >>> Entry.objects.annotate(search=vector).filter(
    ...     search=SearchQuery(Lexeme("Pizza") | Lexeme("Cheese"))
    ... )
    <QuerySet [<Entry: Cheese on Toast recipes>, <Entry: Pizza recipes>]>
    >>> Entry.objects.annotate(search=vector).filter(
    ...     search=SearchQuery(Lexeme("Pizza") | Lexeme("Cheese", weight="A"))
    ... )
    <QuerySet [<Entry: Pizza recipes>]>
    >>> Entry.objects.annotate(search=vector).filter(
    ...     search=SearchQuery(Lexeme("za", prefix=True))
    ... )
    <QuerySet []>

## パフォーマンス

これらの関数を使用するために特別なデータベース設定をする必要はありませんが、数百以上のレコードを検索する場合、パフォーマンスの問題に直面する可能性が高くなります。全文検索は、例えば整数のサイズを比較するよりも負荷の高い処理です。

In the event that all the fields you're querying on are contained within one particular model, you can create a functional `GinIndex` or `GistIndex` which matches the search vector you wish to use. For example:

    GinIndex(
        SearchVector("body_text", "headline", config="english"),
        name="search_vector_idx",
    )

The PostgreSQL docs has details on creating indexes for full text search.

### `SearchVectorField`

class SearchVectorField

この方法が遅すぎる場合は、モデルに `SearchVectorField` を追加できます。このフィールドには、例えば PostgreSQL documentation で説明されているように、トリガーを入力しておく必要があります。そうすれば、あたかもアノテーションされた `SearchVector` のようにフィールドに問い合わせることができます:

    >>> Entry.objects.update(search_vector=SearchVector("body_text"))
    >>> Entry.objects.filter(search_vector="cheese")
    <QuerySet [<Entry: Cheese on Toast recipes>, <Entry: Pizza recipes>]>

### Using `GeneratedField`

An alternative method is to use a `GeneratedField`, which has PostgreSQL maintain the column rather than a trigger:

    from django.contrib.postgres.indexes import GinIndex
    from django.contrib.postgres.search import SearchVector, SearchVectorField
    from django.db import models

    class Entry(models.Model):
        headline = models.CharField(max_length=255)
        body_text = models.TextField()

        search_vector = models.GeneratedField(
            expression=SearchVector("headline", weight="A", config="english")
            + SearchVector("body_text", weight="B", config="english"),
            output_field=SearchVectorField(),
            db_persist=True,
        )

        class Meta:
            indexes = [GinIndex(fields=["search_vector"])]

## trigram（トリグラム）類似度

検索の別の手法として trigram 類似度があります。trigram は3つの連続する文字のグループです。 `trigram_similar`、`trigram_word_similar`、`trigram_strict_word_similar` の他にもいくつかの式を使用できます。

これらを使用するには、PostgreSQL上で pg_trgm 拡張機能 を有効にする必要があります。これは、 `TrigramExtension` マイグレーション・オペレーションを使用してインストールできます。

### `TrigramSimilarity`

class TrigramSimilarity(expression, string, **extra)

フィールド名や式、文字列や式を受け取ります。2つの引数の間の trigram 類似度を返します。

使用例:

    >>> from django.contrib.postgres.search import TrigramSimilarity
    >>> Author.objects.create(name="Katy Stevens")
    >>> Author.objects.create(name="Stephen Keats")
    >>> test = "Katie Stephens"
    >>> Author.objects.annotate(
    ...     similarity=TrigramSimilarity("name", test),
    ... ).filter(
    ...     similarity__gt=0.3
    ... ).order_by("-similarity")
    <QuerySet [<Author: Katy Stevens>, <Author: Stephen Keats>]>

### `TrigramWordSimilarity`

class TrigramWordSimilarity(string, expression, **extra)

文字列または式、およびフィールド名または式を受け入れます。2つの引数間の trigram 単語類似度を返します。

使用例:

    >>> from django.contrib.postgres.search import TrigramWordSimilarity
    >>> Author.objects.create(name="Katy Stevens")
    >>> Author.objects.create(name="Stephen Keats")
    >>> test = "Kat"
    >>> Author.objects.annotate(
    ...     similarity=TrigramWordSimilarity(test, "name"),
    ... ).filter(
    ...     similarity__gt=0.3
    ... ).order_by("-similarity")
    <QuerySet [<Author: Katy Stevens>]>

### `TrigramStrictWordSimilarity`

class TrigramStrictWordSimilarity(string, expression, **extra)

文字列または式とフィールド名または式を受け取り、2つの引数間の trigram 厳密単語類似度を返します。 `TrigramWordSimilarity()` と似ていますが、この関数は範囲境界を単語境界と一致させるように強制します。

### `TrigramDistance`

class TrigramDistance(expression, string, **extra)

フィールド名または式と、文字列または式を受け入れます。2つの引数の間の trigram 距離を返します。

使用例:

    >>> from django.contrib.postgres.search import TrigramDistance
    >>> Author.objects.create(name="Katy Stevens")
    >>> Author.objects.create(name="Stephen Keats")
    >>> test = "Katie Stephens"
    >>> Author.objects.annotate(
    ...     distance=TrigramDistance("name", test),
    ... ).filter(
    ...     distance__lte=0.7
    ... ).order_by("distance")
    <QuerySet [<Author: Katy Stevens>, <Author: Stephen Keats>]>

### `TrigramWordDistance`

class TrigramWordDistance(string, expression, **extra)

文字列または式と、フィールド名または式を受け取ります。2つの引数間の trigram 単語距離を返します。

使用例:

    >>> from django.contrib.postgres.search import TrigramWordDistance
    >>> Author.objects.create(name="Katy Stevens")
    >>> Author.objects.create(name="Stephen Keats")
    >>> test = "Kat"
    >>> Author.objects.annotate(
    ...     distance=TrigramWordDistance(test, "name"),
    ... ).filter(
    ...     distance__lte=0.7
    ... ).order_by("distance")
    <QuerySet [<Author: Katy Stevens>]>

### `TrigramStrictWordDistance`

class TrigramStrictWordDistance(string, expression, **extra)

文字列または式、フィールド名または式を受け入れ、これらの引数間の trigram strict 単語距離を返します。