SQLAlchemy के माध्यम से यादृच्छिक पंक्ति प्राप्त करना


84

SQLAlchemy का उपयोग करके मैं किसी तालिका से एक या अधिक यादृच्छिक पंक्तियों का चयन कैसे करूं?

जवाबों:


124

यह एक डेटाबेस-विशिष्ट समस्या है।

मुझे पता है कि PostgreSQL, SQLite, MySQL और Oracle में एक यादृच्छिक फ़ंक्शन द्वारा ऑर्डर करने की क्षमता है, इसलिए आप SQLAlchemy में इसका उपयोग कर सकते हैं:

from  sqlalchemy.sql.expression import func, select

select.order_by(func.random()) # for PostgreSQL, SQLite

select.order_by(func.rand()) # for MySQL

select.order_by('dbms_random.value') # For Oracle

अगला, आपको क्वेरी को उन रिकॉर्डों की संख्या से सीमित करने की आवश्यकता है जिनकी आपको आवश्यकता है (उदाहरण के लिए उपयोग करके .limit())।

ध्यान रखें कि कम से कम PostgreSQL में, यादृच्छिक रिकॉर्ड का चयन करने से गंभीर पूर्णता संबंधी समस्याएं होती हैं; यहाँ इसके बारे में अच्छा लेख है।


12
+1। Postgres SQLite के लिए काम करता है: select.order_by(func.random()).limit(n)
यांत्रिक_

आप Oracle में order_by ('dbms_random.value') का उपयोग कर सकते हैं।
बटंस .४०

11
यदि आप घोषणात्मक मॉडल का उपयोग कर रहे हैं:session.query(MyModel).order_by(func.rand()).first
ट्रिनिटी

2
धन्यवाद @trinth, यह काम किया जब मैं अंत करने के लिए परोपकारिता जोड़ा:session.query(MyModel).order_by(func.rand()).first()
केंट Munthe Caspersen

3
चूंकि SQLAlchemy v0.4, func.random()एक सामान्य कार्य है जो डेटाबेस के यादृच्छिक कार्यान्वयन के लिए संकलित है।
रज़ेरम

25

यदि आप orm का उपयोग कर रहे हैं और तालिका बड़ी नहीं है (या आपके पास इसकी पंक्तियाँ कैश की गई हैं) और आप चाहते हैं कि यह डेटाबेस से स्वतंत्र हो जो वास्तव में सरल दृष्टिकोण है।

import random
rand = random.randrange(0, session.query(Table).count()) 
row = session.query(Table)[rand]

यह थोड़ा धोखा दे रहा है लेकिन यही कारण है कि आप एक orm का उपयोग करते हैं।


रैंड = रैंडम। अरेंज अरेंजमेंट (0, सेशनरी। टेबल (.count) ())
जेम्स ब्रैडी

आप चुन सकते हैं और सभी वस्तुओं को बनाने से पहले से एक का चयन
सर्ज लालकृष्ण

कैसे के बारे में random.choice(session.query(Table))?
सुलैमान उको

23

एक यादृच्छिक पंक्ति खींचने का एक सरल तरीका है जो आईएस डेटाबेस स्वतंत्र है। बस .offset () का उपयोग करें। सभी पंक्तियों को खींचने की आवश्यकता नहीं है:

import random
query = DBSession.query(Table)
rowCount = int(query.count())
randomRow = query.offset(int(rowCount*random.random())).first()

जहां टेबल आपकी टेबल है (या आप वहां कोई प्रश्न रख सकते हैं)। यदि आप कुछ पंक्तियाँ चाहते हैं, तो आप बस इसे कई बार चला सकते हैं, और यह सुनिश्चित कर सकते हैं कि प्रत्येक पंक्ति पहले की तरह नहीं है।


अद्यतन - mysql में लगभग 10 मिलियन पंक्तियों पर यह वास्तव में थोड़ा धीमा होने लगा, मुझे लगता है कि आप इसे अनुकूलित कर सकते हैं।
गाईसॉफ्ट

1
~ 500k पंक्तियों की सेटिंग में मेरे लिए अच्छी तरह से काम करता है।
मारियो

1
अब Oracle पर 11 मिलियन पंक्तियों पर .... इतना अच्छा नहीं है :-) रैखिक गिरावट, लेकिन अभी भी ... मुझे कुछ और खोजना है।
मारियो

2
@ जयम: आप इस्तेमाल कर सकते हैं query.offset(random.randrange(rowCount)).limit(1).first()
9

1
@ जायमे भी, क्या .limit(1)पहले इस्तेमाल करने का कोई कारण है .first()? यह बेमानी लगता है। शायद, query.offset(random.randrange(row_count)).first()काफी है।
जवानों

17

यहां चार अलग-अलग विविधताएं हैं, जो सबसे धीमी से सबसे तेज करने का आदेश दिया गया है। timeitनीचे परिणाम:

from sqlalchemy.sql import func
from sqlalchemy.orm import load_only

def simple_random():
    return random.choice(model_name.query.all())

def load_only_random():
    return random.choice(model_name.query.options(load_only('id')).all())

def order_by_random():
    return model_name.query.order_by(func.random()).first()

def optimized_random():
    return model_name.query.options(load_only('id')).offset(
            func.floor(
                func.random() *
                db.session.query(func.count(model_name.id))
            )
        ).limit(1).all()

timeit 300 पंक्तियों के साथ एक पोस्टग्रेक्यूएल टेबल के खिलाफ मेरी मैकबुक पर 10,000 रन के लिए परिणाम:

simple_random(): 
    90.09954111799925
load_only_random():
    65.94714171699889
order_by_random():
    23.17819356000109
optimized_random():
    19.87806927999918

आप आसानी से देख सकते हैं कि func.random()पायथन के सभी परिणामों को वापस करने की तुलना में उपयोग करना कहीं अधिक तेज है random.choice()

इसके अलावा, तालिका के आकार में वृद्धि के रूप में, के प्रदर्शन order_by_random()में काफी नीचा होगा, क्योंकि एक ORDER BYएक पूर्ण तालिका स्कैन बनाम की आवश्यकता है COUNTमें optimized_random()एक सूचकांक का उपयोग कर सकते हैं।


नमूने लेने के बारे में क्या? जैसे क्या random.sample()करें? यहाँ अनुकूलित तरीका क्या है?
हमीदज़्ज़म

एक नया प्रश्न खोलें और इसे लिंक करें और मैं उत्तर देने के लिए एक छुरा लूंगा। यदि संभव हो, तो एसक्यूएल के अंतर्निहित स्वाद को निर्दिष्ट करें जो उत्तर को भी प्रभावित करता है।
जेफ विडमैन

क्या यह उपयोग नहीं है flask-sqlalchemy?
मैटसोम

3

कुछ SQL DBMS, अर्थात् Microsoft SQL सर्वर, DB2 और PostgreSQL ने SQL: 2003 TABLESAMPLEक्लॉज लागू किया है । 1.1 संस्करण में SQLAlchemy में समर्थन जोड़ा गया था । यह विभिन्न नमूने विधियों का उपयोग करके तालिका का एक नमूना वापस करने की अनुमति देता है - मानक की आवश्यकता होती है SYSTEMऔर BERNOULLI, जो तालिका के वांछित अनुमानित प्रतिशत को वापस करते हैं।

SQLAlchemy में FromClause.tablesample()और निर्माण tablesample()करने के लिए उपयोग किया जाता है TableSample:

# Approx. 1%, using SYSTEM method
sample1 = mytable.tablesample(1)

# Approx. 1%, using BERNOULLI method
sample2 = mytable.tablesample(func.bernoulli(1))

मैप की गई कक्षाओं के साथ उपयोग किए जाने पर थोड़ी गोटा होती है: TableSampleमॉडल ऑब्जेक्ट को क्वेरी करने के लिए उपयोग किए जाने के लिए उत्पादित वस्तु को अलियास किया जाना चाहिए:

sample = aliased(MyModel, tablesample(MyModel, 1))
res = session.query(sample).all()

चूंकि कई उत्तरों में प्रदर्शन बेंचमार्क होते हैं, इसलिए मैं यहां कुछ सरल परीक्षण भी शामिल करूंगा। लगभग एक लाख पंक्तियों और एक पूर्णांक स्तंभ के साथ PostgreSQL में एक साधारण तालिका का उपयोग करते हुए, 1% नमूना चुनें (लगभग):

In [24]: %%timeit
    ...: foo.select().\
    ...:     order_by(func.random()).\
    ...:     limit(select([func.round(func.count() * 0.01)]).
    ...:           select_from(foo).
    ...:           as_scalar()).\
    ...:     execute().\
    ...:     fetchall()
    ...: 
307 ms ± 5.72 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

In [25]: %timeit foo.tablesample(1).select().execute().fetchall()
6.36 ms ± 188 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

In [26]: %timeit foo.tablesample(func.bernoulli(1)).select().execute().fetchall()
19.8 ms ± 381 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)

SYSTEMनमूनाकरण विधि का उपयोग करने के लिए दौड़ने से पहले, किसी को यह पता होना चाहिए कि यह पृष्ठों का नमूना लेता है , न कि व्यक्तिगत टुपल्स का, इसलिए यह छोटी तालिकाओं के लिए उपयुक्त नहीं हो सकता है, उदाहरण के लिए, और यादृच्छिक परिणाम के रूप में उत्पादन नहीं हो सकता है, यदि तालिका को क्लस्टर किया जाता है।


0

यह मेरे द्वारा उपयोग किया जाने वाला समाधान है:

from random import randint

rows_query = session.query(Table)                # get all rows
if rows_query.count() > 0:                       # make sure there's at least 1 row
    rand_index = randint(0,rows_query.count()-1) # get random index to rows 
    rand_row   = rows_query.all()[rand_index]    # use random index to get random row

1
यह बड़े तालिकाओं पर अविश्वसनीय रूप से धीमा होगा। आप हर एक पंक्ति को हथियाने और फिर इसे ऊपर ले जाएगा।
मैथ्यू

1
वाह, यह महान नहीं है। यदि तालिका रिकॉर्ड गणना प्राप्त करने के लिए कोई क्वेरी है, तो यह एक बेहतर तरीका होगा। यह एक वेब-ऐप पर एक छोटे डीबी के साथ किया गया था, जो अब उस कंपनी के साथ काम नहीं कर रहा है, इसलिए मैं इसके बारे में बहुत कुछ नहीं कर सकता।
चिकनफेट

0

यह एक तालिका की यादृच्छिक पंक्ति (ओं) का चयन करने के लिए मेरा कार्य है:

from sqlalchemy.sql.expression import func

def random_find_rows(sample_num):
    if not sample_num:
        return []

    session = DBSession()
    return session.query(Table).order_by(func.random()).limit(sample_num).all()

-1

डेटाबेस से एक यादृच्छिक सवाल चुनने पर इस उदाहरण का सबसे सरल विधि का उपयोग करें: -

#first import the random module
import random

#then choose what ever Model you want inside random.choise() method
get_questions = random.choice(Question.query.all())

1. क्या होगा अगर डेटाबेस में एक लाख रिकॉर्ड हैं? 2. क्या हमें उन सभी को प्राप्त करना चाहिए और एक यादृच्छिक का चयन करना चाहिए? क्या यह महंगी कॉल नहीं होगी?
सौरव बादामी

1
बिल्कुल एक महंगी कॉल होगी, लेकिन उसने केवल यादृच्छिक विधि के लिए कहा, यह नहीं पूछते कि "डेटा की एक विशिष्ट श्रेणी के साथ या किसी विशिष्ट कुंजी के साथ यादृच्छिक क्वेरी कैसे करें", इसलिए यदि मैंने जवाब दिया और विचार किया कि आपने क्या उल्लेख किया है, तो वह होगा पूरी तरह से अलग विषय हो। मैंने उतने ही सरल उत्तर देने का प्रयास किया जितना कि मैं कर सकता हूं यह स्पष्ट और केवल सटीक जांच के लिए होगा। लोग लाइनों के साथ जवाब देते हैं जबकि यह सरल हो सकता है।
अनस

-2

यह समाधान एकल यादृच्छिक पंक्ति का चयन करेगा

इस समाधान के लिए आवश्यक है कि प्राथमिक कुंजी को नाम दिया गया है, यह होना चाहिए यदि इसकी पहले से ही नहीं:

import random
max_model_id = YourModel.query.order_by(YourModel.id.desc())[0].id
random_id = random.randrange(0,max_model_id)
random_row = YourModel.query.get(random_id)
print random_row

4
यह तब विफल होता है जब आपकी आईडी में अंतर हो।
erickrf

-6

एसक्यूएल के माध्यम से कुछ तरीके हैं, जिसके आधार पर डेटा बेस का उपयोग किया जा रहा है।

(मुझे लगता है कि SQLAlchemy इन सभी का उपयोग कर सकता है)

माई एसक्यूएल:

SELECT colum FROM table
ORDER BY RAND()
LIMIT 1

PostgreSQL:

SELECT column FROM table
ORDER BY RANDOM()
LIMIT 1

MSSQL:

SELECT TOP 1 column FROM table
ORDER BY NEWID()

आईबीएम DB2:

SELECT column, RAND() as IDX
FROM table
ORDER BY IDX FETCH FIRST 1 ROWS ONLY

आकाशवाणी:

SELECT column FROM
(SELECT column FROM table
ORDER BY dbms_random.value)
WHERE rownum = 1

हालाँकि मुझे किसी मानक तरीके की जानकारी नहीं है


7
हाँ। मुझे पता है कि इसे एसक्यूएल में कैसे किया जाता है (मैंने उस उत्तर को Beta.stackoverflow.com/questions/19412/… ) में पोस्ट किया था, लेकिन SQLAlchemy विशिष्ट समाधान के लिए खोज कर रहा था।
cnn
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.