1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168
|
.. _multiple-indexes-label:
Multiple search indexes
=======================
So far, we have only used one class in the ``index_classes`` attribute of our serializers. However, you are able to specify
a list of them. This can be useful when your search engine has indexed multiple models and you want to provide aggregate
results across two or more of them. To use the default multiple index support, simply add multiple indexes the ``index_classes``
list
.. code-block:: python
class PersonIndex(indexes.SearchIndex, indexes.Indexable):
text = indexes.CharField(document=True, use_template=True)
firstname = indexes.CharField(model_attr="first_name")
lastname = indexes.CharField(model_attr="last_name")
def get_model(self):
return Person
class PlaceIndex(indexes.SearchIndex, indexes.Indexable):
text = indexes.CharField(document=True, use_template=True)
address = indexes.CharField(model_attr="address")
def get_model(self):
return Place
class ThingIndex(indexes.SearchIndex, indexes.Indexable):
text = indexes.CharField(document=True, use_template=True)
name = indexes.CharField(model_attr="name")
def get_model(self):
return Thing
class AggregateSerializer(HaystackSerializer):
class Meta:
index_classes = [PersonIndex, PlaceIndex, ThingIndex]
fields = ["firstname", "lastname", "address", "name"]
class AggregateSearchViewSet(HaystackViewSet):
serializer_class = AggregateSerializer
.. note::
The ``AggregateSearchViewSet`` class above omits the optional ``index_models`` attribute. This way results from all the
models are returned.
The result from searches using multiple indexes is a list of objects, each of which contains only the fields appropriate to
the model from which the result came. For instance if a search returned a list containing one each of the above models, it
might look like the following:
.. code-block:: javascript
[
{
"text": "John Doe",
"firstname": "John",
"lastname": "Doe"
},
{
"text": "123 Doe Street",
"address": "123 Doe Street"
},
{
"text": "Doe",
"name": "Doe"
}
]
Declared fields
---------------
You can include field declarations in the serializer class like normal. Depending on how they are named, they will be
treated as common fields and added to every result or as specific to results from a particular index.
Common fields are declared as you would any serializer field. Index-specific fields must be prefixed with "_<index class name>__".
The following example illustrates this usage:
.. code-block:: python
class AggregateSerializer(HaystackSerializer):
extra = serializers.SerializerMethodField()
_ThingIndex__number = serializers.SerializerMethodField()
class Meta:
index_classes = [PersonIndex, PlaceIndex, ThingIndex]
fields = ["firstname", "lastname", "address", "name"]
def get_extra(self,instance):
return "whatever"
def get__ThingIndex__number(self,instance):
return 42
The results of a search might then look like the following:
.. code-block:: javascript
[
{
"text": "John Doe",
"firstname": "John",
"lastname": "Doe",
"extra": "whatever"
},
{
"text": "123 Doe Street",
"address": "123 Doe Street",
"extra": "whatever"
},
{
"text": "Doe",
"name": "Doe",
"extra": "whatever",
"number": 42
}
]
Multiple Serializers
--------------------
Alternatively, you can specify a 'serializers' attribute on your Meta class to use a different serializer class
for different indexes as show below:
.. code-block:: python
class AggregateSearchSerializer(HaystackSerializer):
class Meta:
serializers = {
PersonIndex: PersonSearchSerializer,
PlaceIndex: PlaceSearchSerializer,
ThingIndex: ThingSearchSerializer
}
The ``serializers`` attribute is the important thing here, It's a dictionary with ``SearchIndex`` classes as
keys and ``Serializer`` classes as values. Each result in the list of results from a search that contained
items from multiple indexes would be serialized according to the appropriate serializer.
.. warning::
If a field name is shared across serializers, and one serializer overrides the field mapping, the overridden
mapping will be used for *all* serializers. See the example below for more details.
.. code-block:: python
from rest_framework import serializers
class PersonSearchSerializer(HaystackSerializer):
# NOTE: This override will be used for both Person and Place objects.
name = serializers.SerializerMethodField()
class Meta:
fields = ['name']
class PlaceSearchSerializer(HaystackSerializer):
class Meta:
fields = ['name']
class AggregateSearchSerializer(HaystackSerializer):
class Meta:
serializers = {
PersonIndex: PersonSearchSerializer,
PlaceIndex: PlaceSearchSerializer,
ThingIndex: ThingSearchSerializer
}
|