使用 nosql 排名的 SQLalchemy 中的排序和分页
Posted
技术标签:
【中文标题】使用 nosql 排名的 SQLalchemy 中的排序和分页【英文标题】:Ordering and pagination in SQL-alchemy using non-sql ranking 【发布时间】:2014-08-24 23:20:33 【问题描述】:我有一个 python 算法,它返回给定用户的数据库行的排名顺序。该算法输出一个主键 ID 列表(这些键可以与 post.id 连接)。如下所示,除了可能有数千个匹配项:
result_rank = [1286, 1956, 6759, 3485, 2309, 3409, 9023, 912, 13098, 23489, 19023, 1239]
我想指示 sqlalchemy 选择这些行,并按照它们在列表中的顺序对它们进行排序。问题是我想对此执行pagination
results = posts.query().filter(posts.id.in_(
resultIds)).order_by(??? how can I order by post.id = result_rank ???).paginate(page_num, posts_per_page)
我使用 Postgresql 作为数据库。
【问题讨论】:
我遇到了完全相同的问题。 您使用哪个数据库后端? @van 在我的例子中是 postgres。我不知道 mgoldwasser 两个问题:(1)给定用户的帖子排名多久变化一次? (2) 你的排名算法是否需要读取数据库中的所有帖子,或者不这样做也可以工作? @Miguel 作为赏金的作者,我会相应地回答我的情况。我正在考虑实时排名,因此每次用户看到该页面时,都会处理排名。每个帖子都有一个分数,与其他帖子相关。所以,是的,我需要处理所有帖子。您如何看待我在下面帖子中的评论? 【参考方案1】:除非有好的解决方案,否则我将自己破解分页对象:
class paginate_obj:
""" Pagination dummy object. Takes a list and paginates it similar to sqlalchemy paginate() """
def __init__(self, paginatable, page, per_page):
self.has_next = (len(paginatable)/per_page) > page
self.has_prev = bool(page - 1)
self.next = page + self.has_next
self.prev = page - self.has_prev
self.items = paginatable[(page-1)*(per_page):(page)*(per_page)]
我认为进行排序的唯一方法是创建一个所有结果的列表,并根据一些 lambda 函数在 python 中对其进行排序:
results = my_table.query().all()
results.sort(key=lamba x: distance(x.lat, x.long, user_lat, user_long)
paginated_results = paginate_obj(results, 1, 10) #returns the first page of 10 elements
【讨论】:
【参考方案2】:我认为排序更重要,因为没有它,数据库级别的分页完全没有用。注意到这一点后,我的答案根本不涉及分页方面,但我认为即使@mgoldwasser 提供的答案也可以用于此。
这是我想出的,以便能够选择一些对象并根据初始过滤器列表保留它们的顺序。代码不言自明:
# input
post_ids = [3, 4, 1]
# create helper (temporary in-query table with two columns: post_id, sort_order)
# this table looks like this:
# key | sort_order
# 3 | 0
# 4 | 1
# 1 | 2
q_subq = "\nUNION ALL\n".join(
"SELECT AS key, AS sort_order".format(_id, i)
for i, _id in enumerate(post_ids)
)
# wrap it in a `Selectable` so that we can use JOINs
s = (select([literal_column("key", Integer),
literal_column("sort_order", Integer)])
.select_from(text("() AS helper".format(text(q_subq))))
).alias("helper")
# actual query which is both the filter and sorter
q = (session.query(Post)
.join(s, Post.id == s.c.key) # INNER JOIN will filter implicitly
.order_by(s.c.sort_order) # apply sort order
)
它适用于postgresql
和sqlite
。
【讨论】:
我认为最简单的方法就是使用 context_processor,创建子列表除以总页码,然后为列表中的每个元素运行一个特定的查询 filter_by=X。问题是分页小部件,但这可以手动完成。只需将列表的总元素除以页面总数即可。无论如何,我会等待检查是否有这样做的 orm 友好的。以上是关于使用 nosql 排名的 SQLalchemy 中的排序和分页的主要内容,如果未能解决你的问题,请参考以下文章