Beispiel #1
0
    def count(self):
        """
        Return the number of hits matching the query and filters. Note that
        only the actual number is returned.
        """
        if hasattr(self, '_response'):
            if self._response_async:
                f = Future()
                f.set_result(self._response.hits.total)
                return f
            else:
                return self._response.hits.total

        es = connections.get_connection(self._using)

        d = self.to_dict(count=True)
        # TODO: failed shards detection
        response = es.count(index=self._index,
                            doc_type=self._doc_type,
                            body=d,
                            **self._params)

        if isawaitable(response):
            return future_response(response, lambda r: r['count'])
        else:
            return response['count']
Beispiel #2
0
    def execute(self, ignore_cache=False):
        """
        Execute the search and return an instance of ``Response`` wrapping all
        the data.

        :arg response_class: optional subclass of ``Response`` to use instead.
        """
        if ignore_cache or not hasattr(self, '_response'):
            es = connections.get_connection(self._using)
            response = es.search(index=self._index,
                                 doc_type=self._doc_type,
                                 body=self.to_dict(),
                                 **self._params)

            if isawaitable(response):
                self._response_async = True

                def _build_response(result):
                    self._response = self._response_class(self, result)
                    return self._response

                return future_response(response, _build_response)
            else:
                self._response_async = False
                self._response = self._response_class(self, response)
                return self._response

        if self._response_async:
            f = Future()
            f.set_result(self._response)
            return f
        else:
            return self._response
Beispiel #3
0
    def get(cls, id, using=None, index=None, **kwargs):
        """
        Retrieve a single document from elasticsearch using it's ``id``.

        :arg id: ``id`` of the document to be retireved
        :arg index: elasticsearch index to use, if the ``DocType`` is
            associated with an index this can be omitted.
        :arg using: connection alias to use, defaults to ``'default'``

        Any additional keyword arguments will be passed to
        ``Elasticsearch.get`` unchanged.
        """
        es = connections.get_connection(using or cls._doc_type.using)
        response = es.get(
            index=index or cls._doc_type.index,
            doc_type=cls._doc_type.name,
            id=id,
            **kwargs
        )

        def _build_response(result):
            if not result['found']:
                return None
            return cls.from_es(result)

        return _build_response(response) if not isawaitable(response) else future_response(response, _build_response)
Beispiel #4
0
    def close(self, **kwargs):
        """
        Closes the index in elasticsearch.

        Any additional keyword arguments will be passed to
        ``Elasticsearch.indices.close`` unchanged.
        """
        response = self.connection.indices.close(index=self._name, **kwargs)
        return response if not isawaitable(response) else future_response(
            response, lambda r: r)
Beispiel #5
0
    def flush(self, **kwargs):
        """
        Preforms a flush operation on the index.

        Any additional keyword arguments will be passed to
        ``Elasticsearch.indices.flush`` unchanged.
        """
        response = self.connection.indices.flush(index=self._name, **kwargs)
        return response if not isawaitable(response) else future_response(
            response, lambda r: r)
Beispiel #6
0
    def exists(self, **kwargs):
        """
        Returns ``True`` if the index already exists in elasticsearch.

        Any additional keyword arguments will be passed to
        ``Elasticsearch.indices.exists`` unchanged.
        """
        response = self.connection.indices.exists(index=self._name, **kwargs)
        return response if not isawaitable(response) else future_response(
            response, lambda r: r)
Beispiel #7
0
    def execute_suggest(self):
        """
        Execute just the suggesters. Ignores all parts of the request that are
        not relevant, including ``query`` and ``doc_type``.
        """
        es = connections.get_connection(self._using)
        response = es.suggest(index=self._index,
                              body=self._suggest,
                              **self._params)

        if isawaitable(response):
            return future_response(response, lambda r: SuggestResponse(r))
        else:
            return SuggestResponse(response)
Beispiel #8
0
    def update(self, using=None, index=None, **fields):
        """
        Partial update of the document, specify fields you wish to update and
        both the instance and the document in elasticsearch will be updated::

            doc = MyDocument(title='Document Title!')
            doc.save()
            doc.update(title='New Document Title!')

        :arg index: elasticsearch index to use, if the ``DocType`` is
            associated with an index this can be omitted.
        :arg using: connection alias to use, defaults to ``'default'``

        Any additional keyword arguments will be passed to
        ``Elasticsearch.update`` unchanged.
        """
        if not fields:
            raise IllegalOperation('You cannot call update() without updating individual fields. '
                                   'If you wish to update the entire object use save().')
        es = self._get_connection(using)

        # update the data locally
        merge(self._d_, fields)

        # extract parent, routing etc from meta
        doc_meta = dict(
            (k, self.meta[k])
            for k in DOC_META_FIELDS
            if k in self.meta
        )

        response = es.update(
            index=self._get_index(index),
            doc_type=self._doc_type.name,
            body={'doc': fields},
            **doc_meta
        )

        def _set_meta(meta):
            # update meta information from ES
            for k in META_FIELDS:
                if '_' + k in meta:
                    setattr(self.meta, k, meta['_' + k])

        return _set_meta(response) if not isawaitable(response) else future_response(response, _set_meta)
Beispiel #9
0
    def save(self, using=None, index=None, validate=True, **kwargs):
        """
        Save the document into elasticsearch. If the document doesn't exist it
        is created, it is overwritten otherwise. Returns ``True`` if this
        operations resulted in new document being created.

        :arg index: elasticsearch index to use, if the ``DocType`` is
            associated with an index this can be omitted.
        :arg using: connection alias to use, defaults to ``'default'``
        :arg validate: set to ``False`` to skip validating the document

        Any additional keyword arguments will be passed to
        ``Elasticsearch.index`` unchanged.
        """
        if validate:
            self.full_clean()

        es = self._get_connection(using)
        # extract parent, routing etc from meta
        doc_meta = dict(
            (k, self.meta[k])
            for k in DOC_META_FIELDS
            if k in self.meta
        )
        doc_meta.update(kwargs)

        response = es.index(
            index=self._get_index(index),
            doc_type=self._doc_type.name,
            body=self.to_dict(),
            **doc_meta
        )

        def _set_meta(meta):
            # update meta information from ES
            for k in META_FIELDS:
                if '_' + k in meta:
                    setattr(self.meta, k, meta['_' + k])

            # return True/False if the document has been created/updated
            return meta['created']

        return _set_meta(response) if not isawaitable(response) else future_response(response, _set_meta)
Beispiel #10
0
    def execute(self, ignore_cache=False, raise_on_error=True):
        """
        Execute the multi search request and return a list of search results.
        """
        if ignore_cache or not hasattr(self, '_response'):
            es = connections.get_connection(self._using)

            response = es.msearch(index=self._index,
                                  doc_type=self._doc_type,
                                  body=self.to_dict(),
                                  **self._params)

            def _build_response(data):
                out = []
                for s, r in zip(self._searches, data['responses']):
                    if r.get('error', False):
                        if raise_on_error:
                            raise TransportError('N/A', r['error']['type'],
                                                 r['error'])
                        r = None
                    else:
                        r = Response(s, r)
                    out.append(r)
                self._response = out
                return self._response

            if isawaitable(response):
                self._response_async = True
                return future_response(response, _build_response)
            else:
                return _build_response(response)

        if self._response_async:
            f = Future()
            f.set_result(self._response)
            return f
        else:
            return self._response
Beispiel #11
0
    def mget(cls, docs, using=None, index=None, raise_on_error=True,
             missing='none', **kwargs):
        """
        Retrieve multiple document by their ``id``\s. Returns a list of instances
        in the same order as requested.

        :arg docs: list of ``id``\s of the documents to be retireved or a list
            of document specifications as per
            https://www.elastic.co/guide/en/elasticsearch/reference/current/docs-multi-get.html
        :arg index: elasticsearch index to use, if the ``DocType`` is
            associated with an index this can be omitted.
        :arg using: connection alias to use, defaults to ``'default'``
        :arg missing: what to do when one of the documents requested is not
            found. Valid options are ``'none'`` (use ``None``), ``'raise'`` (raise
            ``NotFoundError``) or ``'skip'`` (ignore the missing document).

        Any additional keyword arguments will be passed to
        ``Elasticsearch.mget`` unchanged.
        """
        if missing not in ('raise', 'skip', 'none'):
            raise ValueError("'missing' must be 'raise', 'skip', or 'none'.")
        es = connections.get_connection(using or cls._doc_type.using)
        body = {
            'docs': [
                doc if isinstance(doc, collections.Mapping) else {'_id': doc}
                for doc in docs
            ]
        }

        response = es.mget(
            body,
            index=index or cls._doc_type.index,
            doc_type=cls._doc_type.name,
            **kwargs
        )

        def _build_response(result):
            objs, error_docs, missing_docs = [], [], []
            for doc in result['docs']:
                if doc.get('found'):
                    if error_docs or missing_docs:
                        # We're going to raise an exception anyway, so avoid an
                        # expensive call to cls.from_es().
                        continue

                    objs.append(cls.from_es(doc))

                elif doc.get('error'):
                    if raise_on_error:
                        error_docs.append(doc)
                    if missing == 'none':
                        objs.append(None)

                # The doc didn't cause an error, but the doc also wasn't found.
                elif missing == 'raise':
                    missing_docs.append(doc)
                elif missing == 'none':
                    objs.append(None)

            if error_docs:
                error_ids = [doc['_id'] for doc in error_docs]
                message = 'Required routing/parent not provided for documents %s.'
                message %= ', '.join(error_ids)
                raise RequestError(400, message, error_docs)
            if missing_docs:
                missing_ids = [doc['_id'] for doc in missing_docs]
                message = 'Documents %s not found.' % ', '.join(missing_ids)
                raise NotFoundError(404, message, missing_docs)
            return objs

        return _build_response(response) if not isawaitable(response) else future_response(response, _build_response)