Как сделан текущий/требуемый функционал сейчас (с помощью Django ORM).
Есть три модели, нужно посчитать количество используемых ингридиентов в каждом ресторане,
делаем это с помощью «backward relationships».
Данные модели имеют ту же структуру, что и оригинальные, но здесь просто
отличаются названия - так что не надо кричать нафига оно нужно так делать.
# models.py
class Restaurant(models.Model):
name = models.CharField(max_length=128)
dishes = models.ManyToManyField('Dish', related_name="restaurant_dish")
class Dish(models.Model):
ingredient = models.ForeignKey('Ingredient', related_name="dish")
description = models.CharField(max_length=512)
class Ingredient(models.Model):
name = models.CharField(max_length=256)
# views.py
# select ingredients, related to Restaurants, with current query in name
ingredients = Ingredient.objects.filter(dish__restaurant_dish__name__icontains=query).distinct()
# count all Restaurants, where ingredients are used. order by number of dishes (descending), then by id.
ingredients = Ingredient.objects.filter(id__in=[a.id for a in ingredients])
ingredients = ingredients.annotate(restaurant_count=Count('dish')).order_by('-restaurant_count', 'id')
получаем такое.
for entry in ingredients:
print "%s (used in %s Restaurants)" % (entry.name, entry.restaurant_count)
"ingredient1 second third word (used in 24 Restaurants)"[br]
"ingredient2 second third word (used in 10 Restaurants)"[br]
то что нужно. ок.
делаем используя Haystack:
объявлем индекс
class RestaurantIndex(indexes.SearchIndex):
name = indexes.CharField(document=True, model_attr='name')
ingredients = indexes.MultiValueField(faceted=True)
def prepare(self, obj):
self.prepared_data = super(RestaurantIndex, self).prepare(obj)
# ["ingredient1 second third word", "ingredient2 second third word",]
self.prepared_data['ingredients'] = [c.ingredient.name for c in obj.dish.all()]
return self.prepared_data
обновляем индекс и тестим:
>>> sqs = SearchQuerySet().all().facet('ingredients')
>>> sqs.facet_counts()
{'dates': {},
'fields': {u'ingredients': [(u'ingredient1', 24),
(u'ingredient2', 10),}
'queries': {}}
Получаем только одно (первое слово) в фасете: «ingredient1» вместо «ingredient1 second third word».
Нужно как-то сделать так, чтобы использовать фасетный поиск, учитывающий полное словосочетание.
В общем, в доках указано что можно искать несколько слов, только вот не могу понять как.
В примерах, у них также ищется по одному слову в фасете.
Думаю, если фасеты могут строиться в цепочки, то надо плясать от этого.
it gives document counts based on words in the corpus, date ranges, numeric ranges or even advanced queries