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']
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
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)
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)
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)
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)
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)
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)
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)
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
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)