2015-02-15 4 views
2

Я пишу новостное приложение, и я хочу, чтобы мои пользователи выбирали любимые источники новостей из списка, содержащего десятки (~ 60) источников (Guardian, Times, ...). У меня есть объект новостей, который содержит индексный источник «источник», и я ищу подход, который позволит мне обойти ограничение 30 подзапросов, наложенных App Engine, которые мешают мне использовать фильтры IN и EQUALS для получения всех новостей который принадлежит большому списку источников.Обходное ограничение 30 подзапросов GAE

есть ли обходной путь для этого ограничения?

Благодаря

ответ

0

С 60 источников, если пользователь хочет N > 30 из них, вы можете разделить взаимодействие в 2-х запросов (по одному на 30, второй для остальных) и объединить результаты самостоятельно. Конечно, существуют практические ограничения, так как вы не хотите, конечно, заканчивать несвязанное количество запросов, но это должно быть значительно выше ваших текущих 60 источников без слишком большого количества проблем.

Например, в Python, чтобы создать список запросов:

def many_source_queries(sources): 
    queries = [] 
    for i in range(0, len(sources), 30): 
     queries.append(News.source.IN(sources[i:i+30])) 
    return queries 

затем сливаться на результаты нескольких запросов есть, конечно, много подходов, но упрощенно тот, где вы просто извлечь все в списке довольно тривиально:

def fetch_many_queries(queries): 
    return [x for q in queries for x in q.fetch()] 

конечно, вы можете добавить фильтры, заказ (и сделать heapq.merge из потоков, чтобы сохранить полученный заказ), и т.д., и т.д. Я просто обращаясь к «30 подзапросам ограничения».

Добавлено: это только масштабируется до определенной точки (например, по количеству источников, желаемых в запросе). Например, если объекты могут иметь (скажем) 600 разных источников, а запрос хочет 300 из них, вы получите около половины возвращаемого вам хранилища данных (если количество новостей на источник примерно равномерно), и это не имеет смысла делать 10 отдельных запросов для этой цели.

IOW, как я уже писал, выше «Существуют практические ограничения, так как вы не хотите заканчивать несвязанным количеством запросов». При обнаружении запроса для более чем порогового N источников (большая часть содержимого магазина) я предпочел бы сделать один запрос без фильтра источника и выборочно игнорировать объекты с «неправильными источниками» на уровне приложения).

Так что в этом случае я бы другой подход, например ..:

import itertools as it 

def supermany_source_queries(sources): 
    return News.query(), set(sources) 

def next_up_to_n(n, news_query, sources_set): 
    def goodnews(news): return news.source in sources_set 
    while True: 
     page = list(it.islice(it.ifilter(goodnews, news_query), n)) 
     if not page: break 
     yield page 

Здесь код магистральный бы первым назвать

q, ss = supermany_source_queries(sources) 

затем подготовить точный запрос eq от q с любой .filter и/или .order может потребоваться, а затем петли, например

for onepage in next_up_to_n(pagesize, eq, ss): 
    deal_with_page(onepage) 

Конечно, это может быть учтено несколькими различными способами (возможно, лучше всего с пользовательским классом, способным принять другое решение в зависимости от количества запрашиваемых источников), но еще раз я хочу выделить общий идея, то есть ..: вместо использования огромного количества отдельных запросов для сотен источников, когда вы в любом случае получаете большую часть хранилища данных, используйте один запрос (так что смиритесь с тем, чтобы встать во все хранилище данных вместо , скажем, половину его, в зависимости от других фильтров и возможного раннего завершения в deal_with_page), и используйте итерацию и выбор на уровне приложения (с itertools & c) для игнорирования объектов, которые фактически не представляют интереса.

+0

Спасибо @alex, список может вырасти до сотен источников в будущем, поддерживаете ли вы свой подход к запросу хранилища данных сотнями фильтров. Есть ли лучший подход для этой конфигурации? – Hakim

+0

@Hakim, нет, если типичный запрос требует (скажем) 300 источников, превращая их в 10 обращений в хранилище данных, становится довольно чрезмерным (это намного меньше, чем количество источников в сущности, гораздо больше, сколько в запросах) ; как я писал: «Существуют практические ограничения, так как вы не хотите заканчивать несвязанным количеством запросов». При обнаружении запроса более чем на некотором пороге N источников (большая часть содержимого магазина) я предпочел бы сделать один запрос без фильтра источника и выборочно игнорировать объекты с «неправильными источниками» на уровне приложения). Хм, я отредактирую A, чтобы добавить это. –

2

Помните, что индексы дороги - они занимают много места и умножают затраты на запись.

Я использовал бы другой дизайн. Вместо 60 подзапросов (и что произойдет, если ваш список источников вырастет до 500?), Я бы сделал свойство source unindexed. Затем я загрузил список всех последних новостей и сохранил их в Memcache. Если вы его потеряете, вы всегда можете его перезагрузить. Вы также можете легко добавить в этот список еще несколько элементов, поскольку новости поступают. Вы также можете разбить этот список на куски в зависимости от времени.

Теперь, когда пользователи выполняют свои вызовы, вы можете легко отфильтровать этот список в памяти. В зависимости от объема использования этот дизайн будет десятки - или в тысячи раз дешевле и работает намного быстрее. Самое большое различие заключается в том, что вместо того, чтобы читать одни и те же объекты снова и снова для каждого пользовательского запроса, вы будете читать их один раз и обслуживать тысячи запросов, прежде чем их нужно будет снова прочитать.

+0

Спасибо @Andrei Список источников может расти справедливо сотнями источников после перехода на региональные. Я не уверен, что дизайн, который вы предложили, оптимален для спецификаций моего приложения, таких как бесконечная прокрутка и фильтрация сложностей (самые рейтинговые, просмотренные, прокомментированные новости, относящиеся к определенной группе источников). Я не хочу делать все это самостоятельно. Более того, я уже реализовал уровень кэша, сервер и клиентскую сторону, чтобы минимизировать запрос к хранилищу данных. – Hakim

+0

На самом деле эти требования делают этот дизайн еще более привлекательным. Пока вы сохраняете последний список новостей в Memcache, вы избегаете запросов к базе данных с уникальной комбинацией критериев поиска для каждого пользователя. –

Смежные вопросы