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