Skip to content

Commit

Permalink
Basic persistence documentation
Browse files Browse the repository at this point in the history
  • Loading branch information
honzakral committed Jan 23, 2015
1 parent 2d08e8d commit 80f7e0e
Show file tree
Hide file tree
Showing 2 changed files with 173 additions and 0 deletions.
3 changes: 3 additions & 0 deletions docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,8 @@ In this example you can see:

* accessing the underlying client for other APIs

You can see more in the :ref:`persistence` chapter.

Migration from ``elasticsearch-py``
-----------------------------------

Expand Down Expand Up @@ -208,5 +210,6 @@ Contents

configuration
search_dsl
persistence
Changelog

170 changes: 170 additions & 0 deletions docs/persistence.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@
.. _persistence:

Persistence
===========

You can use the dsl library to define your mappings and a basic persistent
layer for your application.

Mappings
--------

The mapping definition follows a similar pattern to the query dsl:

.. code:: python
from elasticsearch_dsl import Mapping, String, Nested
# name your type
m = Mapping('my-type')
# add fields
m = m.field('title', 'string')
# you can use multi-fields easily
m = m.field('category', 'string', fields={'raw': String(index='not_analyzed')})
# you can also create a field manually
comment = Nested().field('author', 'string').field('created_at', 'date')
# and attach it to the mapping
m = m.field('comments', comment)
# save the mapping into index 'my-index'
m.save('my-index')
Especially if you are using dynamic mappings it might be useful to update the
mapping based on an existing type in Elasticsearch, or create the mapping
directly from an existing type:

.. code:: python
# get the mapping from our production cluster
m = Mapping.from_es('my-index', 'my-type', using='prod')
# update based on data in QA cluster
m.update_from_es('my-index', using='qa')
# update the mapping on production
m.save('my-index', using='prod')
DocType
-------

If you want to create a model-like wrapper around your documents, use the
``DocType`` class:

.. code:: python
from datetime import datetime
from elasticsearch_dsl import DocType, String, Date, Nested, Boolean
class Post(DocType):
title = String()
created_at = Date()
published = Boolean()
category = String(fields={'raw': String(index='not_analyzed')})
comments = Nested(
properties={
'author': String(fields={'raw': String(index='not_analyzed')}),
'content': String(analyzer='snowball'),
'created_at': Date()
}
)
class Meta:
index = 'blog'
def add_comment(self, author, content):
self.comments.append(
{'author': author, 'content': content})
def save(self, ** kwargs):
self.created_at = datetime.now()
return super().save(** kwargs)
To create a new ``Post`` document just instantiate the class and pass in any
fields you wish to set, you can then use standard attribute setting to
change/add more fields. Note that you are not limitted to the fields defined
explicitly:

.. code:: python
# instatiate the document
first = Post(title='My First Blog Post, yay!', published=True)
# assign some field values, can be values or lists of values
first.category = ['everything', 'nothing']
# every document has an id
first.id = 42
# save the document into the cluster
first.save()
To retrieve an existing document use the ``get`` class method:

.. code:: python
# retrieve the document
first = Post.get(id=42)
# now we can call methods, change fields, ...
first.add_comment('me', 'This is nice!')
# and save the changes into the cluster again
first.save()
To search for this document type, use the ``search`` class method:

.. code:: python
# by calling .search we get back a standard Search object
s = Post.search()
# the search is already limitted to the index and doc_type of our document
s = s.filter('term', published=True).query('match', title='first')
results = s.execute()
# when you execute the search the results are wrapped in your document class (Post)
for posts in results:
print(post._meta.score, post.title)
Alternatively you can just take a ``Search`` object and restrict it to return
our document type, wrapped in correct class:

.. code:: python
s = Search()
s = s.doc_type(Post)
You can also combine document classes with standard doc types (just strings),
which will be treated as before. You can also pass in multiple ``DocType``
subclasses and each document in the response will be wrapped in it's class.

To delete a document just call its ``delete`` method:

.. code:: python
first = Post.get(id=42)
first.delete()
``class Meta`` options
~~~~~~~~~~~~~~~~~~~~~~

In the ``Meta`` class inside your document definition you can define various
metadata for your document:

``doc_type``
name of the doc_type in elasticsearch. By default it will be constructed from
the class name (MyDocument -> my_document)

``index``
default index for the document, by default it is empty and every operation
such as ``get`` or ``save`` requires an explicit ``index`` parameter

``using``
default connection alias to use, defaults to ``'default'``

``mapping``
optional instance of ``Mapping`` class to use as base for the mappings
created from the fields on the document class itself

0 comments on commit 80f7e0e

Please sign in to comment.