Skip to content

Commit

Permalink
docs: improve configuration documentation
Browse files Browse the repository at this point in the history
Fix grammar and formatting issues. Ensure the code examples work.
  • Loading branch information
jpvanhal committed Aug 25, 2023
1 parent 4501e93 commit a6b6b78
Show file tree
Hide file tree
Showing 3 changed files with 77 additions and 99 deletions.
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

0 comments on commit a6b6b78

Please sign in to comment.