Last active
March 5, 2019 10:41
-
-
Save Geekfish/9184976 to your computer and use it in GitHub Desktop.
Postgres order by rand
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
""" | |
This is to allow grabing a random set of rows, | |
in a repeatable way (for example, if you need to ensure that | |
a user always sees the same "random" set of results). | |
Method one sets the seed in Postgres. | |
It's using order by RANDOM(), so it can be extremely slow | |
for large querysets. | |
Method two is significantly faster, as we are generating | |
the random ids in python, but it will only work properly | |
if the ids are sequential. | |
A workaround, if there can be some occasional small gaps, | |
would be selecting more results than needed and use the extras | |
to fill any holes (not demonstrated here but not too hard to do). | |
""" | |
def using_setseed(queryset): | |
""" Simple but horribly slow, also returns a RawQuerySet. """ | |
raw_sql = str(queryset.extra(select={'sort_key': 'random()'}) | |
.order_by('sort_key').query) | |
set_seed = "SELECT setseed(%s);" % float(random_seed) | |
return queryset.model.objects.raw(set_seed + raw_sql) | |
def using_id_in(queryset, random_seed): | |
""" Faster but kind of ugly SQL. | |
Ordering is done with: | |
ORDER BY | |
CASE | |
WHEN id=10 THEN 0 | |
WHEN id=2 THEN 1 | |
WHEN id=1 THEN 2 | |
... | |
END; | |
""" | |
random.seed(random_seed) | |
last_id = queryset.order_by('-id')[0].id | |
random_ids = random.sample(xrange(1, last_id + 1), last_id) | |
clauses = ' '.join([ | |
'WHEN id=%s THEN %s' % (pk, i) | |
for i, pk in enumerate(random_ids) | |
]) | |
ordering = 'CASE %s END' % clauses | |
queryset = queryset.filter(id__in=random_ids).extra( | |
select={'ordering': ordering}, order_by=('ordering',)) | |
return queryset |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Hi,
I've applied following function too. But i am getting an error.
Here is my full code.
Can you please help me? thanks a lot.