Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

docs: improve configuration documentation #137

Merged
merged 1 commit into from
Aug 25, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
167 changes: 69 additions & 98 deletions docs/configuration.rst
Original file line number Diff line number Diff line change
@@ -1,169 +1,140 @@
Configuration
=============

.. currentmodule:: sqlalchemy_searchable

SQLAlchemy-Searchable provides a number of customization options for the automatically generated
search trigger, index and search_vector columns.
search trigger, index and search vector columns.

Global configuration options
----------------------------

The following configuration options can be defined globally by passing them to make_searchable function.

* search_trigger_name - name of the search database trigger, default: {table}_search_update

* search_trigger_function_name - the name for the database search vector updating function.
The following configuration options can be defined globally by passing them to
:func:`make_searchable` function:

* regconfig - postgresql regconfig to be used, default: pg_catalog.english
``search_trigger_name``
Defines the name of the search database trigger. The default naming
convention is ``"{table}_{column}_trigger"``.

Example ::
``search_trigger_function_name``
Defines the name of the database search vector updating function. The
default naming convention is ``{table}_{column}_update``.

``regconfig``
This is the PostgreSQL text search configuration that determines the
language configuration used for searching. The default setting is
``"pg_catalog.english"``.

make_searchable(Base.metadata, options={'regconfig': 'pg_catalog.finnish'})
Here's an example of how to leverage these options::

make_searchable(Base.metadata, options={"regconfig": "pg_catalog.finnish"})

Changing catalog for search vector
----------------------------------


In the following example we use Finnish regconfig instead of the default English one.
::

In some cases, you might want to switch from the default language configuration
to another language for your search vector. You can achieve this by providing
the ``regconfig`` parameter for the
:class:`~sqlalchemy_utils.types.ts_vector.TSVectorType`. In the following
example, we use Finnish instead of the default English one::

class Article(Base):
__tablename__ = 'article'
__tablename__ = "article"

name = sa.Column(sa.Unicode(255))

search_vector = TSVectorType('name', regconfig='pg_catalog.finnish')
name = sa.Column(sa.Text(255))
search_vector = TSVectorType("name", regconfig="pg_catalog.finnish")

Weighting search results
------------------------

PostgreSQL supports `weighting search terms`_ with weights A through D.

In this example, we give higher priority to terms appearing in the article title than in the content.
::

To further refine your search results, PostgreSQL's `term weighting system`_
(ranging from A to D) can be applied. This example demonstrates how to
prioritize terms found in the article title over those in the content::

class Article(Base):
__tablename__ = 'article'

title = sa.Column(sa.Unicode(255))
content = sa.Column(sa.UnicodeText)
__tablename__ = "article"

id = sa.Column(sa.Integer, primary_key=True)
title = sa.Column(sa.String(255))
content = sa.Column(sa.Text)
search_vector = sa.Column(
TSVectorType('title', 'content',
weights={'title': 'A', 'content': 'B'})
TSVectorType("title", "content", weights={"title": "A", "content": "B"})
)

Note that in order to see the effect of this weighting, you must search with ``sort=True``

::
Remember, when working with weighted search terms, you need to conduct your
searches using the ``sort=True`` option::

query = session.query(Article)
query = search(query, 'search text', sort=True)
query = search(sa.select(Article), "search text", sort=True)

.. _term weighting system: http://www.postgresql.org/docs/current/static/textsearch-controls.html#TEXTSEARCH-PARSING-DOCUMENTS

Multiple search vectors per class
---------------------------------

::
In cases where a model requires multiple search vectors, SQLAlchemy-Searchable
has you covered. Here's how you can set up multiple search vectors for an
``Article`` class::

class Article(Base):
__tablename__ = 'article'
__tablename__ = "article"

id = sa.Column(sa.Integer, primary_key=True)
name = sa.Column(sa.Unicode(255))
content = sa.Column(sa.UnicodeText)
description = sa.Column(sa.UnicodeText)
simple_search_vector = sa.Column(TSVectorType('name'))

fat_search_vector = sa.Column(
TSVectorType('name', 'content', 'description')
)
name = sa.Column(sa.String(255))
content = sa.Column(sa.Text)
description = sa.Column(sa.Text)
simple_search_vector = sa.Column(TSVectorType("name"))

fat_search_vector = sa.Column(TSVectorType("name", "content", "description"))

After that, we can choose which search vector to use.
::

query = session.query(Article)
query = search(query, 'first', vector=fat_search_vector)
You can then choose which search vector to use when querying::

query = search(sa.select(Article), "first", vector=Article.fat_search_vector)

Combined search vectors
-----------------------

Sometimes you may want to search from multiple tables at the same time. This can be achieved using
combined search vectors.

Consider the following model definition. Here each article has one category.

::


Sometimes you may want to search from multiple tables at the same time. This can
be achieved using combined search vectors. Consider the following model
definition where each article has one category::

import sqlalchemy as sa
from sqlalchemy.orm import declarative_base

from sqlalchemy_utils.types import TSVectorType


Base = declarative_base()


class Category(Base):
__tablename__ = 'category'
__tablename__ = "category"

id = sa.Column(sa.Integer, primary_key=True)
name = sa.Column(sa.Unicode(255))
search_vector = sa.Column(TSVectorType('name'))
name = sa.Column(sa.String(255))
search_vector = sa.Column(TSVectorType("name"))


class Article(Base):
__tablename__ = 'article'
__tablename__ = "article"

id = sa.Column(sa.Integer, primary_key=True)
name = sa.Column(sa.Unicode(255))
content = sa.Column(sa.UnicodeText)
search_vector = sa.Column(TSVectorType('name', 'content'))
category_id = sa.Column(
sa.Integer,
sa.ForeignKey(Category.id)
)
name = sa.Column(sa.String(255))
content = sa.Column(sa.Text)
search_vector = sa.Column(TSVectorType("name", "content"))
category_id = sa.Column(sa.Integer, sa.ForeignKey(Category.id))
category = sa.orm.relationship(Category)


Now consider a situation where we want to find all articles, where either article content or name or category name contains the word 'matrix'. This can be achieved as follows:

::


import sqlalchemy as sa

search_query = u'matrix'
Now consider a situation where we want to find all articles where either article
content or name or category name contains the word "matrix". This can be
achieved as follows::

combined_search_vector = Article.search_vector | Category.search_vector

articles = (
session.query(Article)
.join(Category)
.filter(
combined_search_vector.match(
sa.func.tsq_parse(search_query)
)
)
query = search(
sa.select(Article).join(Category), "matrix", vector=combined_search_vector
)

This query becomes a little more complex when using left joins. Then, you have
to take into account situations where ``Category.search_vector`` might be
``None`` using the ``coalesce`` function::

This query becomes a little more complex when using left joins. Then you have to take into account situations where Category.search_vector is None using coalesce function.

::


combined_search_vector = (
Article.search_vector
|
sa.func.coalesce(Category.search_vector, u'')
combined_search_vector = Article.search_vector | sa.func.coalesce(
Category.search_vector, ""
)

.. _weighting search terms: http://www.postgresql.org/docs/current/static/textsearch-controls.html#TEXTSEARCH-PARSING-DOCUMENTS
3 changes: 2 additions & 1 deletion docs/quickstart.rst
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
Quick start
===========

.. currentmodule:: sqlalchemy_searchable

Installation
------------

Expand Down Expand Up @@ -92,7 +94,6 @@ function::
API
---

.. module:: sqlalchemy_searchable
.. autofunction:: make_searchable
.. autofunction:: search

6 changes: 6 additions & 0 deletions sqlalchemy_searchable/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -449,6 +449,12 @@ def downgrade():


def make_searchable(metadata, mapper=sa.orm.Mapper, manager=search_manager, options={}):
"""
Configure SQLAlchemy-Searchable for given SQLAlchemy metadata object.

:param metadata: SQLAlchemy metadata object
:param options: Dictionary of configuration options
"""
manager.options.update(options)
event.listen(mapper, "instrument_class", manager.process_mapper)
event.listen(mapper, "after_configured", manager.attach_ddl_listeners)
Expand Down