2009-07-31 4 views
1

Мне понравилось создавать пару простых приложений на GAE, но теперь я смущен тем, как архитектор организатора музыкальной коллекции в движке приложения. Короче говоря, я не могу понять, как фильтровать несколько свойств при сортировке по другой.Фильтровать и сортировать информацию о музыке в Google App Engine

Давайте предположим, что основная модель является альбомом, который содержит несколько свойств, в том числе:

  • Названия
  • Исполнитель
  • Этикетка
  • Публикации Год
  • Жанр
  • Длина
  • Список названий треков
  • Список настроений
  • кодировки даты вставки в базу данных

Давайте также предположим, что я хотел бы, чтобы фильтровать всю коллекцию, используя эти свойства, а затем сортировки результатов по одному из:

  • год издания
  • Длина альбома
  • Исполнитель название
  • Когда была добавлена ​​информация я в базе данных

Я не знаю, как это сделать, не набегая на взрывоопасный индексный головоломка. В частности, я хотел бы сделать что-то вроде:

Albums.all().filter('publication_year <', 1980).order('artist_name') 

Я знаю, что это невозможно, но то, что обходной путь?

Это похоже на довольно общий вид применения. Музыкальные альбомы могут быть ресторанами, бутылками вина или отелями. У меня есть набор элементов с дескриптивными свойствами, которые я хотел бы фильтровать и сортировать.

Есть ли образец модели данных с лучшей практикой, с которой я не обращаю внимания? Любой совет?

ответ

1

Здесь есть несколько вариантов: вы можете фильтровать как можно лучше, а затем сортировать результаты в памяти, как предлагает Алекс, или вы можете переделать свои структуры данных для фильтров равенства вместо фильтров неравенства.

Например, если вы хотите фильтровать только десятилетие, вы можете добавить поле, кодирующее десятилетие, в котором была записана песня. Чтобы найти все до или после десятилетия, сделайте запрос IN в течение десятилетий, которые вы хотите охватить. Для этого потребуется один базовый запрос за десятилетие, но если количество записей велико, это все равно может быть дешевле, чем выборки всех результатов и их сортировка в памяти.

+0

Это (переработка для выравнивающих фильтров) на самом деле то, что предложил Бретт в своем разговоре GoogleIO: http://code.google.com/events/io/sessions/BuildingScalableComplexApps.html. Я бы предложил посмотреть его - действительно проницательный. –

+0

Я был там в то время, поэтому мне не нужно его смотреть. ;) –

0

Как вы говорите, вы не можете иметь условие неравенства для одного поля и порядок другим (или неравенства в двух полях и т. Д. И т. Д.). Обходной путь - просто использовать условие «наилучшего» неравенства для получения данных в памяти (где «лучший» означает тот, который, как ожидается, даст наименьшие данные), а затем уточнить его и заказать его с помощью кода Python в вашем приложении.

списковых языка Python (и других форм петель & с), sort метод Листа и встроенной функцией sorted, то itertools модуля в стандартной библиотеке, и так далее, все это помогает много, чтобы сделать эти виды задач достаточно просто выполнить в Python.

+0

Спасибо за ответ. У меня сложилось впечатление, что я должен приложить все усилия, чтобы избежать вычислений с целью избежать исчерпания ресурсов GAE. С другой стороны, сортировка нескольких сотен (не более 1000) предметов - не сложная задача. Вы делали эти типы в движке приложения при возврате результатов? Усиливает ли он ограничения ресурсов? – Greg

+0

Я их сделал, и это далеко не доходит до 30-секундного срока. На моем ноутбуке сортировка случайно перетасованного списка из 1000 предметов занимает около 500 микросекунд, и я подозреваю, что серверы GAE быстрее моего ноутбука ;-) –

+0

@Alex: вы не учитываете стоимость извлечения и декодирования 1000 объектов, хотя , что является значительным. –

1

Поскольку хранилище дешево, вы можете создать свои собственные индексные файлы на основе ListProperty с ключевыми словами, которые отражают критерии сортировки.

class album_pubyear_List(db.Model): 
    words = db.StringListProperty() 

class album_length_List(db.Model): 
    words = db.StringListProperty() 

class album_artist_List(db.Model): 
    words = db.StringListProperty() 

class Album(db.Model): 
    blah... 

    def save(self): 
     super(Album, self).save() 

     # you could do this at save time or batch it and do 
     # it with a cronjob or taskqueue 

     words = [] 

     for field in ["title", "artist", "label", "genre", ...]: 
      words.append("%s:%s" %(field, getattr(self, field))) 

     word_records = [] 
     now = repr(time.time()) 
     word_records.append(album_pubyear_List(parent=self, key_name="%s_%s" %(self.pubyear, now)), words=words) 
     word_records.append(album_length_List(parent=self, key_name="%s_%s" %(self.album_length, now)), words=words) 
     word_records.append(album_artist_List(parent=self, key_name="%s_%s" %(self.artist_name, now)), words=words) 
     db.put(word_records) 

Теперь, когда пришло время искать вам создать соответствующую ИНЕКЕ и вызвать соответствующую модель

where = "WHERE words = " + "%s:%s" %(field-a, value-a) + " AND " + "%s:%s" %(field-b, value-b) etc. 
aModel = "album_pubyear_List" # or anyone of the other key_name sorted wordlist models 

indexes = db.GqlQuery("""SELECT __key__ from %s %s""" %(aModel, where)) 
keys = [k.parent() for k in indexes[offset:numresults+1]] # +1 for pagination 
object_list = db.get(keys) # returns a sorted by key_name list of Albums 
Смежные вопросы