Package: elasticstack
Version:0.5.0Author:Ben Lopatin (http://benlopatin.com)Configurable indexing and other extras for Haystack (with ElasticSearch
biases).Full documentation is onRead the Docs.RequirementsDjango: tested against Django 1.8, and 1.9Haystack: tested against Haystack 2.4.0,
it should work with any combination of Haystack and Django that workElasticSearch: presumably any newish
version will do, however the only version tested against so far is 0.19.xFeatures and goalsSome of these features are backend agnostic but most features have
ElasticSearch in mind.For more background see the blog postStretching Haystack’s ElasticSearch Backend.Global configurable index mappingThe search mapping provided by Haystack’s ElasticSearch backend includes brief
but sensible defaults for nGram analysis. You can globaly add change these settings or
add your own mappings by providing a mapping dictionary usingELASTICSEARCH_INDEX_SETTINGSin your settings file. This example takes the
default mapping and adds a synonym analyzer:ELASTICSEARCH_INDEX_SETTINGS = {
    'settings': {
        "analysis": {
            "analyzer": {
                "synonym_analyzer" : {
                    "type": "custom",
                    "tokenizer" : "standard",
                    "filter" : ["synonym"]
                },
                "ngram_analyzer": {
                    "type": "custom",
                    "tokenizer": "lowercase",
                    "filter": ["haystack_ngram", "synonym"]
                },
                "edgengram_analyzer": {
                    "type": "custom",
                    "tokenizer": "lowercase",
                    "filter": ["haystack_edgengram"]
                }
            },
            "tokenizer": {
                "haystack_ngram_tokenizer": {
                    "type": "nGram",
                    "min_gram": 3,
                    "max_gram": 15,
                },
                "haystack_edgengram_tokenizer": {
                    "type": "edgeNGram",
                    "min_gram": 2,
                    "max_gram": 15,
                    "side": "front"
                }
            },
            "filter": {
                "haystack_ngram": {
                    "type": "nGram",
                    "min_gram": 3,
                    "max_gram": 15
                },
                "haystack_edgengram": {
                    "type": "edgeNGram",
                    "min_gram": 2,
                    "max_gram": 15
                },
                "synonym" : {
                    "type" : "synonym",
                    "ignore_case": "true",
                    "synonyms_path" : "synonyms.txt"
                }
            }
        }
    }
}The synonym filter is ready for your index, but will go unused yet.Before your new analyzer can be used you will need to change your Haystack engine and rebuild/update
your index. In yoursettings.pymodifyHAYSTACK_CONNECTIONSaccordingly:HAYSTACK_CONNECTIONS = {
    'default': {
        'ENGINE': 'elasticstack.backends.ConfigurableElasticSearchEngine',
        'URL': env_var('HAYSTACK_URL', 'http://127.0.0.1:9200/'),
        'INDEX_NAME': 'haystack',
    },
}The default analyzer for non-nGram fields in Haystack’s ElasticSearch backend
is thesnowball analyzer.
A perfectly good analyzer but not necessarily what you need. It’s also language
specific (English by default).Specify your analyzer withELASTICSEARCH_DEFAULT_ANALYZERin your settings
file:ELASTICSEARCH_DEFAULT_ANALYZER = 'synonym_analyzer'Now all your analyzed fields, except for nGram fields, will be analyzed usingsynonym_analyzer.If you want to specify a custom search_analyzer for nGram/EdgeNgram fields,
define it with theELASTICSEARCH_DEFAULT_NGRAM_SEARCH_ANALYZERsettings:ELASTICSEARCH_DEFAULT_NGRAM_SEARCH_ANALYZER = 'standard'Configurable index mapping per indexAlternatively you can configure index mapping per index. This is usefull for multilanguage index settup.
In this caseHAYSTACK_CONNECTIONcontains keySETTINGS_NAMEhave to match with name inELASTICSEARCH_INDEX_SETTINGS:HAYSTACK_CONNECTIONS = {
    'default': {
        'ENGINE': 'elasticstack.backends.ConfigurableElasticSearchEngine',
        'URL': env_var('HAYSTACK_URL', 'http://127.0.0.1:9200/'),
        'INDEX_NAME': 'haystack',
        'SETTINGS_NAME': 'cs',
        'DEFAULT_ANALYZER': 'czech_hunspell',
        'DEFAULT_NGRAM_SEARCH_ANALYZER': 'standard',
    },
}

ELASTICSEARCH_INDEX_SETTINGS = {
    'cs': {
        "settings": {
            "analysis": {
                "analyzer": {
                    "czech_hunspell": {
                        "type": "custom",
                        "tokenizer": "standard",
                        "filter": ["stopwords_CZ", "lowercase", "hunspell_CZ", "stopwords_CZ", "remove_duplicities"]
                    }
                },
                "filter": {
                    "stopwords_CZ": {
                        "type": "stop",
                        "stopwords": ["právě", "že", "test", "_czech_"],
                        "ignore_case": True
                    },
                    "hunspell_CZ": {
                        "type": "hunspell",
                        "locale": "cs_CZ",
                        "dedup": True,
                        "recursion_level": 0
                    },
                    "remove_duplicities": {
                        "type": "unique",
                        "only_on_same_position": True
                    },
                }
            }
        }
    },
}Field based analysisEven with a new default analyzer you may want to change this on a field by
field basis as fits your needs. To do so, use the fields fromelasticstack.fieldsto specify your analyzer with theanalyzerkeyword
argument:from haystack import indexes
from elasticstack.fields import CharField
from myapp.models import MyContent

class MyContentIndex(indexes.SearchIndex, indexes.Indexable):
    text = CharField(document=True, use_template=True,
            analyzer='synonym_analyzer')

    def get_model(self):
        return MyContentDjango CBV style viewsHaystacks’s class based views predate the inclusion of CBVs into the Django
core and so the paradigms are different. This makes it harder to impossible to
make use of view mixins.The bundledSearchViewandFacetedSearchViewclasses are based ondjango.views.generic.edit.FormViewusing theSearchMixinandFacetedSearchMixin, respectively. TheSearchMixinprovides the necessary
search related attributes and overloads the form processing methods to execute
the search.TheSearchMixinadds a few search specific attributes:load_all- a Boolean value forspecifying database lookupsqueryset- a defaultSearchQuerySet. Defaults toEmtpySearchQuerySetsearch_field- the name of the form field used for the query. This is added
to allow for views which may have more than one search form. Defaults toq.NoteTheSearchMixinuses the attribute namedquerysetfor the resultantSearchQuerySet. Naming this attributesearchquerysetwould make more
sense semantically and hew closer to Haystack’s naming convention, however
by using thequerysetattribute shared by other Django view mixins it is
relatively easy to combine search functionality with other mixins and
views.Management commandsshow_mappingMake a change and wonder why your results don’t look as expected? The
management commandshow_mappingwill print the current mapping for
your defined search index(es). At the least it may show that you’ve simply
forgotten to update your index with new mappings:python manage.py show_mappingBy default this will display theexisting_mappingwhich shows the index,
document type, and document properties.:{
    "haystack": {
        "modelresult": {
            "properties": {
                "is_active": {
                    "type": "boolean"
                },
                "text": {
                    "type": "string"
                },
                "published": {
                    "type": "date",
                    "format": "dateOptionalTime"
                }
            }
        }
    }
}If you provide the–detailflag this will return only the field mappings but
including additional details, such as boost levels and field-specific
analyzers.:{
    "is_active": {
        "index": "not_analyzed",
        "boost": 1,
        "store": "yes",
        "type": "boolean"
    },
    "text": {
        "index": "analyzed",
        "term_vector": "with_positions_offsets",
        "type": "string",
        "analyzer": "custom_analyzer",
        "boost": 1,
        "store": "yes"
    },
    "pub_date": {
        "index": "analyzed",
        "boost": 1,
        "store": "yes",
        "type": "date"
    }
}show_documentProvided the name of an indexed model and a key it generates and prints the
generated document for this object:python manage.py show_document myapp.MyModel 19181The JSON document will be formatted with ‘pretty’ indenting.Stability, docs, and testsThe form, view, and backend functionality in this project is considered stable.
Test coverage is not substantial, but is run against Django 1.8 through Django
1.10 on Python 2.7, 3.4, and 3.5.Why not add this stuff to Haystack?This project first aims to solve problems related specifically to working with
ElasticSearch. Haystack is 1) backend agnostic (a good thing), 2) needs to
support existing codebases, and 3) not my project. Most importantly, adding
these features through a separate Django app means providing them without
needing to fork Haystack. Hopefully some of the features here, once finalized
and tested, will be suitable to add to Haystack.History0.5.0 (2017-03-17)Replace deprecated option_list in commands with add_arguments methodUpdate Django versions in tox config and docs0.4.1 (2016-05-05)Fix encoding issue in installation. In at least one known environment/Python3
combination an encoding issue prevented installation of the package.0.4.0 (2016-01-28)Allow changing search settings on an index-by-index basis0.3.0 (2015-12-31)Set default analyzer for ngram fields0.2.0 (2015-09-29)Switch to py.testTests against Django 1.8, 1.9Drop pyelasticsearch requirement for installation0.1.1 (2015-01-13)Bug fix in show_document management command0.1.0 (2014-11-24)Major structural changesBugfix for configurable search fields0.0.6 (2013-10-04)Require pyelasticsearch for installation0.0.5 (2013-09-28)Fixed reference to old method0.0.4 (2013-09-28)Search form can search using specified field nameAdded management command to output mapping for an individual
document0.0.3 (2013-09-28)Added default analyzer setting0.0.2 (2013-09-28)Packaging fix0.0.1 (2013-09-28)Initial release