Source code for parasolr.query.aliased_queryset

from typing import Dict, List

from parasolr.query.queryset import SolrQuerySet


[docs]class AliasedSolrQuerySet(SolrQuerySet): """Extension of :class:`~parasolr.query.queryset.SolrQuerySet` with support for aliasing Solr fields to more readable versions for use in code. To use, extend this class and define a dictionary of :attr:`field_aliases` with the same syntax you would when calling :meth:`only`. Those field aliases will be set as the default initial value for :attr:`field_list`, and aliases can be used in all extended methods. """ #: map of application-specific, readable field names #: to actual solr fields (i.e. if using dynamic field types) field_aliases = {} def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) # set default field list based on field_aliases self.field_list = [ "%s:%s" % (key, value) for key, value in self.field_aliases.items() ] # generate reverse lookup for updating facets & highlights self.reverse_aliases = {val: key for key, val in self.field_aliases.items()}
[docs] def _unalias_args(self, *args): """convert alias name to solr field for list of args""" return [self.field_aliases.get(arg, arg) for arg in args]
[docs] def _unalias_kwargs(self, **kwargs): """convert alias name to solr field for keys in kwargs""" return {self.field_aliases.get(key, key): val for key, val in kwargs.items()}
[docs] def _unalias_kwargs_with_lookups(self, **kwargs): """convert alias name to solr field for keys in kwargs with support for __ lookups for filters""" new_kwargs = {} for key, val in kwargs.items(): field_parts = key.split(self.LOOKUP_SEP, 1) # first part is always present = field name field = field_parts[0] # get alias for key if there is one field = self.field_aliases.get(field, field) # if there is a lookup, add it back to the unaliased field if len(field_parts) > 1: field = "%s__%s" % (field, field_parts[1]) new_kwargs[field] = val return new_kwargs
[docs] def filter(self, *args, tag: str = "", **kwargs) -> "AliasedSolrQuerySet": """Extend :meth:`parasolr.query.queryset.SolrQuerySet.filter` to support using aliased field names for keyword argument keys.""" kwargs = self._unalias_kwargs_with_lookups(**kwargs) return super().filter(*args, tag=tag, **kwargs)
[docs] def facet(self, *args, **kwargs) -> "AliasedSolrQuerySet": """Extend :meth:`parasolr.query.queryset.SolrQuerySet.facet` to support using aliased field names in args.""" args = self._unalias_args(*args) return super().facet(*args, **kwargs)
[docs] def stats(self, *args, **kwargs) -> "AliasedSolrQuerySet": """Extend :meth:`parasolr.query.queryset.SolrQuerySet.stats` to support using aliased field names in args.""" args = self._unalias_args(*args) return super().stats(*args, **kwargs)
[docs] def facet_field( self, field: str, exclude: str = "", **kwargs ) -> "AliasedSolrQuerySet": """Extend :meth:`parasolr.query.queryset.SolrQuerySet.facet_field`` to support using aliased field names for field parameter.""" field = self.field_aliases.get(field, field) return super().facet_field(field, exclude=exclude, **kwargs)
[docs] def order_by(self, *args) -> "AliasedSolrQuerySet": """Extend :meth:`parasolr.query.queryset.SolrQuerySet.order_by`` to support using aliased field names in sort arguments.""" args = self._unalias_args(*args) return super().order_by(*args)
[docs] def only(self, *args, **kwargs) -> "AliasedSolrQuerySet": """Extend :meth:`parasolr.query.queryset.SolrQuerySet.only`` to support using aliased field names for args (but not kwargs).""" # convert args to aliased args, switching them to keyword # args; unknown fields are treated the same way kwargs.update({arg: self.field_aliases.get(arg, arg) for arg in args}) return super().only(**kwargs)
# also method does not need to be extended, since it runs through only
[docs] def highlight(self, field: str, **kwargs) -> "AliasedSolrQuerySet": """Extend :meth:`parasolr.query.queryset.SolrQuerySet.highlight` to support using aliased field names in kwargs.""" field = self.field_aliases.get(field, field) return super().highlight(field, **kwargs)
[docs] def group(self, field: str, **kwargs) -> "AliasedSolrQuerySet": """Extend :meth:`parasolr.query.queryset.SolrQuerySet.group` to support using aliased field names in kwargs. (Note that sorting does not currently support aliased field names).""" field = self.field_aliases.get(field, field) # TODO: should we also reverse alias for sort option if specified? return super().group(field, **kwargs)
[docs] def get_facets(self) -> Dict[str, int]: """Extend :meth:`parasolr.query.queryset.SolrQuerySet.get_facets` to use aliased field names for facet and range facet keys.""" facets = super().get_facets() # bail out if empty dict is returned if not facets: return facets # replace field names in facet field and facet range # with aliased field names for section in ["facet_fields", "facet_ranges"]: facets[section] = { self.reverse_aliases.get(field, field): val for field, val in facets[section].items() } return facets
[docs] def get_stats(self) -> Dict[str, Dict]: """Extend :meth:`parasolr.query.queryset.SolrQuerySet.get_stats` to return return aliased field names for field_list keys.""" stats = super().get_stats() if stats: stats["stats_fields"] = { self.reverse_aliases.get(field, field): val for field, val in stats["stats_fields"].items() } return stats
[docs] def get_highlighting(self) -> Dict[str, Dict[str, List]]: highlighting = super().get_highlighting() # highlighting results are keyed on document id # for each document, there is a dictionary of highlights; # key is field name, value is the list of snippets if highlighting: for doc_id, highlights in highlighting.items(): highlighting[doc_id] = { self.reverse_aliases.get(field, field): snippets for field, snippets in highlights.items() } return highlighting