【问题标题】:Most performant way to retrieve a Django queryset sorted in accordance to a redis sorted set检索根据 redis 排序集排序的 Django 查询集的最高效方法
【发布时间】:2017-01-03 01:11:07
【问题描述】:

我有一个 redis 排序集,其中包含对象 ID 及其各自的排序分数。我需要检索这些对象的 Django 查询集,根据排序集的分数进行排序。最有效的方法是什么?我的数据库是 postgresql。


目前,我正在分别检索 redis 排序集和 未排序 查询集。接下来,我根据排序集在 python 中的分数对查询集进行排序。可以在这里有意义地削减步骤,例如以某种方式在检索点对查询集进行排序等?

    obj_ids_with_scr = get_ids_w_scr() #retrieves redis sorted set with scores
    obj_ids = map(itemgetter(0),obj_ids_with_scr) # filters sorted set for just the obj ids
    queryset = Widget.objects.filter(id__in=obj_ids) #unsorted queryset
    a = dict(obj_ids_with_scr) #turning the sorted set into a dictionary
    for obj_pk, sort_score in a:
        obj = queryset.get(id=obj_pk) #get object with id equalling obj_pk 
        sort_score = obj  #assign the object to the 'score' value of this key-value 
    result = a.values() #making a list of all values, that are now in sorted order
    return result

【问题讨论】:

  • 你用的是什么数据库?
  • 我使用的是 postgresql 9.3

标签: python django sorting redis


【解决方案1】:

如果您使用的是 postgres,则可以通过定义自己的 field function in postgres 来模拟 mysql 的 order by field 语法 here:

CREATE FUNCTION field(anyelement, VARIADIC anyarray) RETURNS numeric AS $$
  SELECT
    COALESCE(
     ( SELECT i FROM generate_subscripts($2, 1) gs(i)
       WHERE $2[i] = $1 ),
     0);
$$ LANGUAGE SQL STABLE

然后用类似这样的方式调用:

queryset = queryset.extra(
    select={'manual': "FIELD(id, %s)" % (','.join(map(str, obj_ids)),) },
    order_by=['manual']
)

n.b.如果您愿意,也可以像这样优化您的 python 代码:

widgets = Widgets.objects.in_bulk(obj_ids)
sorted_widgets = [ widgets[x] for x in obj_ids if x in widgets ]

In-bulk 返回一个 dict 映射 id 到 Widget 实例,这对于您正在执行的排序类型很有用。你可以阅读更多关于它的信息here。

【讨论】:

  • 谢谢。第一种方法非常独特 - 我将尝试一下。第二个更简单,但是in_bulk 是什么?是不是像filter()?
  • in_bulk 类似于过滤器,您可以向它传递一个 ID 列表,它会使用这些 ID 检索 Widgets。它的特别之处还在于它返回一个将id 映射到Widget 的dict。 { x.id: x for x in Widgets.objects.filter(id__in=obj_ids) } 的一种简写形式。
  • 老实说,我从未尝试过。但我认为只要您在 in_bulk 调用之前使用它就应该可以工作(例如,Widget.objects.select_related('widget_parent').in_bulk(obj_ids)
  • 猜猜只有一种方法可以找出答案。感谢您的回答!
猜你喜欢
  • 2016-11-30
  • 2016-10-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-04-14
  • 2012-07-30
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多