Session: Querying: How to Perform a Faceted (Aggregated) Search
To execute facet (aggregation) query via the session query
method, use aggregate_by
,
aggregate_by_facets
, or aggregate_using
.
This will scope you to the aggregation query builder, where you'll be allowed to define
single or multiple facets for the query using a straightforward and fluent API.
Syntax
def aggregate_by(
self, builder_or_facet: Union[Callable[[FacetBuilder], None], FacetBase]
) -> AggregationDocumentQuery[_T]: ...
def aggregate_by_facets(self, facets: List[FacetBase]) -> AggregationDocumentQuery[_T]: ...
def aggregate_using(self, facet_setup_document_id: str) -> AggregationDocumentQuery[_T]: ...
Parameters | ||
---|---|---|
builder_or_facet | Union[Callable[[FacetBuilder], None] |
Builder with a fluent API that constructs a FacetBase instance-or- FacetBase implementation defining the scope of the facet and its options (either Facet or RangeFacet ) |
facets | List[FacetBase] |
Items containing FacetBase implementations |
facet_setup_document_id | str |
ID of a document containing FacetSetup |
Facet & RangeFacet
Facet vs RangeFacet
RangeFacet
allows you to split the results of the calculations into several ranges, in contrast to Facet
where whole spectrum of results will be used to generate a single outcome.
class FacetBase(ABC):
def __init__(self):
self.display_field_name: Union[None, str] = None
self.options: Union[None, FacetOptions] = None
self.aggregations: Dict[FacetAggregation, Set[FacetAggregationField]] = {}
class Facet(FacetBase):
def __init__(self, field_name: str = None):
super().__init__()
self.field_name = field_name
class RangeFacet(FacetBase):
def __init__(self, parent: Optional[FacetBase] = None):
super().__init__()
self.ranges: List[str] = []
class FacetAggregation(enum.Enum):
NONE = "None"
MAX = "Max"
MIN = "Min"
AVERAGE = "Average"
SUM = "Sum"
Builder
def by_ranges(self, range_: RangeBuilder, *ranges: RangeBuilder) -> FacetOperations[_T]: ...
def by_field(self, field_name: str) -> FacetOperations[_T]: ...
def with_display_name(self, display_name: str) -> FacetOperations[_T]: ...
def with_options(self, options: FacetOptions) -> FacetOperations[_T]: ...
def sum_on(self, path: str, display_name: Optional[str] = None) -> FacetOperations[_T]: ...
def min_on(self, path: str, display_name: Optional[str] = None) -> FacetOperations[_T]: ...
def max_on(self, path: str, display_name: Optional[str] = None) -> FacetOperations[_T]: ...
def average_on(self, path: str, display_name: Optional[str] = None) -> FacetOperations[_T]: ...
Parameters | ||
---|---|---|
*ranges | RangeBuilder |
A list of aggregated ranges |
field_name | str |
Points to the index field that should be used for operation (by_ranges , by_field ) or to document field that should be used for aggregation (sum_on , min_on , max_on , average_on ) |
display_name | str |
If set, results of a facet will be returned under this name |
options | FacetOptions |
Non-default options that should be used for operation |
path | str |
Points to the index field that should be used for operation (by_ranges , by_field ) or to document field that should be used for aggregation (sum_on , min_on , max_on , average_on ) |
Options
def __init__(self):
self.page_size: int = constants.int_max
self.start: Union[None, int] = None
self.term_sort_mode: FacetTermSortMode = FacetTermSortMode.VALUE_ASC
self.include_remaining_terms: bool = False
Options | ||
---|---|---|
term_sort_mode | FacetTermSortMode |
Indicates how terms should be sorted (VALUE_ASC , VALUE_DESC , COUNT_ASC , COUNT_DESC ) |
include_remaining_terms | bool |
Indicates if remaining terms should be included in results |
start | Union[None, int] |
Used to skip given number of facet results in the outcome |
page_size | int |
Used to limit facet results to the given value |
Example I
facet_options = FacetOptions.default_options()
facet_options.term_sort_mode = FacetTermSortMode.COUNT_DESC
facet_options.start = 0
facet1 = Facet("manufacturer")
facet1.options = facet_options
facet2 = RangeFacet()
facet2.ranges = [
"cost < 200",
"cost between 200 and 400",
"cost between 400 and 600",
"cost between 600 and 800",
"cost >= 800",
]
facet2.aggregations = {FacetAggregation.AVERAGE: {FacetAggregationField("cost")}}
facet3 = RangeFacet()
facet3.ranges = [
"megapixels < 3",
"megapixels between 3 and 7",
"megapixels between 7 and 10",
"megapixels >= 10",
]
facets = (
session.query_index("Camera/Costs", Camera)
.aggregate_by(facet1)
.and_aggregate_by(facet2)
.and_aggregate_by(facet3)
.execute()
)
from index 'Camera/Costs'
select
facet(manufacturer),
facet(cost < 200, cost >= 200 AND cost < 400, cost >= 400 AND cost < 600, cost >= 600 AND cost < 800, cost >= 800),
facet(megapixels < 3, megapixels >= 3 AND megapixels < 7, megapixels >= 7 AND megapixels < 10, megapixels >= 10)
Example II
options = FacetOptions()
options.start = 0
options.term_sort_mode = FacetTermSortMode.COUNT_DESC
cost_builder = RangeBuilder.for_path("cost")
megapixels_builder = RangeBuilder.for_path("megapixels")
facet_result = (
session.query_index("Camera/Costs", Camera)
.aggregate_by(lambda builder: builder.by_field("manufacturer").with_options(options))
.and_aggregate_by(
lambda builder: builder.by_ranges(
cost_builder.is_less_than(200),
cost_builder.is_greater_than_or_equal_to(200).is_less_than(400),
cost_builder.is_greater_than_or_equal_to(400).is_less_than(600),
cost_builder.is_greater_than_or_equal_to(600).is_less_than(800),
cost_builder.is_greater_than_or_equal_to(800),
).average_on("cost")
)
.and_aggregate_by(
lambda builder: builder.by_ranges(
megapixels_builder.is_less_than(3),
megapixels_builder.is_greater_than_or_equal_to(3).is_less_than(7),
megapixels_builder.is_greater_than_or_equal_to(7).is_less_than(10),
megapixels_builder.is_greater_than_or_equal_to(10),
)
)
).execute()
from index 'Camera/Costs'
select
facet(manufacturer),
facet(cost < 200, cost >= 200 AND cost < 400, cost >= 400 AND cost < 600, cost >= 600 AND cost < 800, cost >= 800),
facet(megapixels < 3, megapixels >= 3 AND megapixels < 7, megapixels >= 7 AND megapixels < 10, megapixels >= 10)
Example III
facet_setup = FacetSetup()
facet_manufacturer = Facet()
facet_manufacturer.field_name = "manufacturer"
facet_setup.facets = [facet_manufacturer]
camera_facet = RangeFacet()
camera_facet.ranges = [
"cost < 200",
"cost between 200 and 400",
"cost between 400 and 600",
"cost between 600 and 800",
"cost >= 800",
]
megapixels_facet = RangeFacet()
megapixels_facet.ranges = [
"megapixels < 3",
"megapixels between 3 and 7",
"megapixels between 7 and 10",
"megapixels >= 10",
]
facet_setup.range_facets = [camera_facet, megapixels_facet]
session.store(facet_setup, "facets/CameraFacets")
session.save_changes()
facets = session.query_index("Camera/Costs", Camera).aggregate_using("facets/CameraFacets").execute()
from index 'Camera/Costs'
select facet(id('facets/CameraFacets'))
aggregate_by
only supports aggregation by a single field.
If you want to aggregate by multiple fields, emit a single field that contains all values.