全文検索
django.contrib.postgres.search
モジュールのデータベース機能により、PostgreSQLの全文検索エンジンを簡単に使用できます。
このドキュメントの例では、クエリの作成で定義されているモデルを使用します。
searchルックアップ
全文検索を使用する一般的な方法は、データベース内の単一の列に対して単一の用語を検索することです。 例えば:
>>> Entry.objects.filter(body_text__search='Cheese')
[<Entry: Cheese on Toast recipes>, <Entry: Pizza Recipes>]
これにより、body_text
フィールドからデータベースにto_tsvector
が作成され、検索語'Cheese'
からplainto_tsquery
が作成されます。どちらも、デフォルトのデータベース検索構成を使用します。 結果は、クエリとベクトルを照合することによって取得されます。
search
ルックアップを使用するには、'django.contrib.postgres'
が:setting: `INSTALLED_APPS` に含まれている必要があります。
バージョン3.1で変更:クエリ式のサポートが追加されました。
SearchVector
- class SearchVector(*expressions, config=None, weight=None)
単一のフィールドに対する検索は素晴らしいですが、かなり制限されます。 検索しているEntry
インスタンスは、tagline
フィールドを持つBlog
に属しています。 両方のフィールドに対してクエリを実行するには、SearchVector
を使用します。
>>> from django.contrib.postgres.search import SearchVector
>>> Entry.objects.annotate(
... search=SearchVector('body_text', 'blog__tagline'),
... ).filter(search='Cheese')
[<Entry: Cheese on Toast recipes>, <Entry: Pizza Recipes>]
SearchVector
の引数には、任意の Expression またはフィールドの名前を指定できます。 複数の引数はスペースを使用して連結されるため、検索ドキュメントにはそれらすべてが含まれます。
SearchVector
オブジェクトを組み合わせて、再利用することができます。 例えば:
>>> Entry.objects.annotate(
... search=SearchVector('body_text') + SearchVector('blog__tagline'),
... ).filter(search='Cheese')
[<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の全文検索ドキュメントをお読みください。 例:
>>> from django.contrib.postgres.search import SearchQuery
>>> 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
の用語を論理的に組み合わせて、柔軟性を高めることができます。
>>> from django.contrib.postgres.search import SearchQuery
>>> SearchQuery('meat') & SearchQuery('cheese') # AND
>>> SearchQuery('meat') | SearchQuery('cheese') # OR
>>> ~SearchQuery('meat') # NOT
config
パラメーターの説明については、検索構成の変更を参照してください。
バージョン3.1で変更: 'websearch'
の検索タイプとSearchQuery.value
のクエリ式のサポートが追加されました。
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')
[<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のドキュメントには、さまざまなランク正規化オプションの詳細が記載されています。
バージョン3.1の新機能: normalization
およびcover_density
パラメーターが追加されました。
SearchHeadline
バージョン3.1の新機能。
- 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
にゼロ以外の整数値を指定して、表示するフラグメントの最大数を設定します。 PostgreSQLではデフォルトで無効になっています。
fragment_delimiter
文字列パラメーターを設定して、フラグメント間の区切り文字を構成します。 PostgreSQLのデフォルトは" ... "
です。
PostgreSQLのドキュメントには、検索結果の強調表示に関する詳細があります。
使用例:
>>> 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
パラメーターの説明については、検索構成の変更を参照してください。
検索構成の変更
config
属性を SearchVector および SearchQuery に指定して、別の検索構成を使用できます。 これにより、データベースで定義されているさまざまな言語のパーサーと辞書を使用できます。
>>> from django.contrib.postgres.search import SearchQuery, SearchVector
>>> Entry.objects.annotate(
... search=SearchVector('body_text', config='french'),
... ).filter(search=SearchQuery('œuf', config='french'))
[<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')))
[<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
を参照します。 それらに異なる重みを付けたい場合は、4つのフロートのリストを 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')
パフォーマンス
これらの機能を使用するために特別なデータベース構成は必要ありませんが、数百を超えるレコードを検索している場合は、パフォーマンスの問題が発生する可能性があります。 たとえば、全文検索は、整数のサイズを比較するよりも集中的なプロセスです。
クエリを実行しているすべてのフィールドが1つの特定のモデルに含まれている場合は、使用する検索ベクトルに一致する機能インデックスを作成できます。 PostgreSQLのドキュメントには、全文検索用のインデックスの作成の詳細が記載されています。
SearchVectorField
- class SearchVectorField
このアプローチが遅くなりすぎる場合は、モデルにSearchVectorField
を追加できます。 たとえば、 PostgreSQLのドキュメントで説明されているように、トリガーを設定しておく必要があります。 次に、注釈付きのSearchVector
であるかのようにフィールドにクエリを実行できます。
>>> Entry.objects.update(search_vector=SearchVector('body_text'))
>>> Entry.objects.filter(search_vector='cheese')
[<Entry: Cheese on Toast recipes>, <Entry: Pizza recipes>]
トリグラムの類似性
検索への別のアプローチは、トリグラムの類似性です。 トリグラムは、3つの連続した文字のグループです。 :lookup: `trigram_similar` ルックアップに加えて、他のいくつかの式を使用できます。
それらを使用するには、PostgreSQLで pg_trgm拡張機能をアクティブ化する必要があります。 TrigramExtension 移行操作を使用してインストールできます。
TrigramSimilarity
- class TrigramSimilarity(expression, string, **extra)
フィールド名または式、および文字列または式を受け入れます。 2つの引数間のトリグラム類似性を返します。
使用例:
>>> 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')
[<Author: Katy Stevens>, <Author: Stephen Keats>]
TrigramDistance
- class TrigramDistance(expression, string, **extra)
フィールド名または式、および文字列または式を受け入れます。 2つの引数間のトリグラム距離を返します。
使用例:
>>> 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')
[<Author: Katy Stevens>, <Author: Stephen Keats>]