Mapping types and Indexables

The MappingType class

elasticutils.MappingType lets you centralize concerns regarding documents you’re storing in your Elasticsearch index.

Lets you tie business logic to search results

When you do searches with MappingTypes, you get back those results as an iterable of MappingTypes by default.

For example, say you had a description field and wanted to have a truncated version of it. You could do it this way:

class MyMappingType(MappingType):

    # ... missing code here

    def description_truncated(self):
        return self.description[:100]

results = S(MyMappingType).query(description__text='stormy night')

print list(results)[0].description_truncated()

DefaultMappingType

The most basic MappingType is the DefaultMappingType which is returned if you don’t specify a MappingType and also don’t call elasticutils.S.values_dict() or elasticutils.S.values_list(). The DefaultMappingType lets you access search result fields as instance attributes or as keys:

res.description
res['description']

The latter syntax is helpful when there are attributes defined on the class that have the same name as the document field or aren’t valid Python names.

For more information

See Types and Mappings for documentation on defining mappings in the index.

See elasticutils.MappingType for documentation on creating MappingTypes.

The Indexable class

elasticutils.Indexable is a mixin for elasticutils.MappingType that has methods and classmethods for making indexing easier.

Example

Here’s an example of a class that subclasses MappingType and Indexable. It’s based on a model called BlogEntry.

class BlogEntryMappingType(MappingType, Indexable):
    @classmethod
    def get_index(cls):
        return 'blog-index'

    @classmethod
    def get_mapping_type_name(cls):
        return 'blog-entry'

    @classmethod
    def get_model(cls):
        return BlogEntry

    @classmethod
    def get_es(cls):
        return get_es(urls=['http://localhost:9200'])

    @classmethod
    def get_mapping(cls):
        return {
            'properties': {
                'id': {'type': 'integer'},
                'title': {'type': 'string'},
                'tags': {'type': 'string'}
            }
        }

    @classmethod
    def extract_document(cls, obj_id, obj=None):
        if obj == None:
            obj = cls.get_model().get(id=obj_id)

        doc = {}
        doc['id'] = obj.id
        doc['title'] = obj.title
        doc['tags'] = obj.tags
        return doc

    @classmethod
    def get_indexable(cls):
        return cls.get_model().get_objects()

With this, I can write code elsewhere in my project that:

  1. gets the mapping type name and mapping for documents of type “blog-entry”
  2. gets all the objects that are indexable
  3. for each object, extracts the Elasticsearch document data and indexes it

When I create my elasticutils.S object, I’d create it like this:

s = S(BlogEntryMappingType)

and now by default any search results I get back are instances of the BlogEntryMappingType class.