অ্যাক্টিভেকর্ডে র্যান্ডম রেকর্ড


151

অ্যাক্টিভেকর্ডের মাধ্যমে আমার কোনও টেবিল থেকে এলোমেলো রেকর্ড পাওয়ার দরকার। আমি 2006 থেকে জামিস বাকের উদাহরণ অনুসরণ করেছি ।

তবে, আমি গুগল অনুসন্ধানের মাধ্যমে অন্যভাবেও এসে পৌঁছেছি (নতুন ব্যবহারকারীর বিধিনিষেধের কারণে কোনও লিঙ্কের সাথে বিশিষ্ট হওয়া যায় না):

 rand_id = rand(Model.count)
 rand_record = Model.first(:conditions => ["id >= ?", rand_id])

আমি আগ্রহী যে এখানকার অন্যরা কীভাবে এটি করেছে বা যদি কেউ জানে যে কোন উপায়টি আরও দক্ষ হবে।


2
2 টি পয়েন্ট যা কোনও উত্তরকে সহায়তা করতে পারে। 1. আপনার আইডিকে কত সমানভাবে বিতরণ করা হয়, সেগুলি কি অনুক্রমিক? ২. এটি কতটা এলোমেলো হওয়া দরকার? যথেষ্ট এলোমেলো, বা বাস্তব এলোমেলো?
মাইকেল

এগুলি ক্রমিক আইডস যা অ্যাক্টিভেকর্ড দ্বারা স্বয়ংক্রিয়ভাবে উত্পন্ন হয় এবং এটি যথেষ্ট ভাল হতে পারে।
জায়ুনারউড

1
তারপরে আপনার প্রস্তাবিত সমাধানটি আদর্শের কাছাকাছি :) আমি COUNT (*) এর পরিবর্তে "SELECT MAX (id) FROM table_name" ব্যবহার করব কারণ এটি মুছে ফেলা সারিগুলি আরও ভালভাবে মোকাবেলা করবে, অন্যথায়, বাকিটি ঠিক আছে। সংক্ষেপে, যদি "যথেষ্ট ভাল" ঠিক থাকে, তবে আপনার কেবল একটি পদ্ধতি থাকতে হবে যা আপনার কাছে যা আছে তার কাছাকাছি একটি বিতরণ ধরে নেয়। এটি অভিন্ন এবং এমনকি যেমনটি আপনি বলেছেন, সরল র‌্যান্ড দুর্দান্ত কাজ করে।
মাইকেল

1
আপনি যখন সারিগুলি মুছবেন তখন এটি কাজ করবে না।
ভেঙ্কট ডি

উত্তর:


136

কমপক্ষে দুটি প্রশ্ন ছাড়া এটি করার কোনও আদর্শ উপায় আমি খুঁজে পাইনি।

নিম্নলিখিতটি অফসেট হিসাবে এলোমেলোভাবে উত্পন্ন সংখ্যা (বর্তমান রেকর্ড গণনা অবধি) ব্যবহার করে ।

offset = rand(Model.count)

# Rails 4
rand_record = Model.offset(offset).first

# Rails 3
rand_record = Model.first(:offset => offset)

সত্যি কথা বলতে, আমি সবেমাত্র র‌্যান্ডের () বা র‌্যান্ডম () (ডাটাবেসের উপর নির্ভর করে) ব্যবহার করছি। আপনার কোনও পারফরম্যান্স সমস্যা না থাকলে এটি কোনও পারফরম্যান্সের সমস্যা নয়।


2
কোড Model.find(:offset => offset).firstত্রুটি নিক্ষেপ করবে। আমি মনে করি Model.first(:offset => offset)আরও ভাল পারফর্ম করতে পারে।
হরিশ শেঠি

1
হ্যাঁ, আমি রেল 3 নিয়ে কাজ করছি এবং সংস্করণগুলির মধ্যে ক্যোয়ারী ফর্ম্যাটগুলি সম্পর্কে বিভ্রান্ত হয়ে পড়ছি।
টবি হেডে

7
নোট করুন যে অফসেটটি ব্যবহার করা বড় ডেটাসেটের সাথে খুব ধীর, কারণ এটির জন্য আসলে সূচক স্ক্যানের প্রয়োজন (বা টেবিল স্ক্যান, যদি ক্লাস্টারড ইনডেক্স ইনোডিবি ব্যবহার করা হয়)। অন্য কথায়, এটি ও (এন) অপারেশন তবে "WHERE id> = # {র্যান্ড_আইডি} অর্ডার বাই আইডি ASC লিমিটেড 1" হ'ল (লগ এন), যা অনেক দ্রুত।
কেন

15
সচেতন থাকুন যে অফসেট-পদ্ধতির ফলে কেবল একটি এলোমেলোভাবে পাওয়া ডেটা পয়েন্ট পাওয়া যায় (প্রথমটি, এরপরেও আইডির মাধ্যমে বাছাই করা হয়)। আপনার যদি একাধিক এলোমেলোভাবে নির্বাচিত রেকর্ডের প্রয়োজন হয় তবে আপনাকে অবশ্যই এই পদ্ধতিটি একাধিকবার ব্যবহার করতে হবে বা আপনার ডাটাবেস দ্বারা প্রদত্ত এলোমেলোভাবে অর্ডার পদ্ধতিটি ব্যবহার করতে হবে, যেমন Thing.order("RANDOM()").limit(100)100 এলোমেলোভাবে নির্বাচিত এন্ট্রিগুলির জন্য। (সচেতন থাকুন যে এটি RANDOM()পোস্টগ্রাসএসকিউএল এবং RAND()মাইএসকিউএল ... আপনি যতটা পোর্টেবল হতে চান তেমন নয়)
ফ্লোরিয়ান পিলজ

3
4 রেলগুলিতে আমার জন্য কাজ করে না Use ব্যবহার করুন Model.offset(offset).first
মাহেমফ

206

রেল 6

মন্তব্যে জেসন দ্বারা বর্ণিত হিসাবে, রেল 6 এ, অ-গুণাবলী যুক্তি অনুমোদিত নয়। আপনাকে অবশ্যই একটি Arel.sql()বিবৃতিতে মানটি আবৃত করতে হবে ।

Model.order(Arel.sql('RANDOM()')).first

পাখি 5, 4

ইন পাগল 4 এবং 5 ব্যবহার PostgreSQL বা SQLite ব্যবহার RANDOM():

Model.order('RANDOM()').first

সম্ভবত মাইএসকিউএল এর সাথে একই কাজ করবেRAND()

Model.order('RAND()').first

এই সম্পর্কে 2.5 গুণ বেশি দ্রুত মধ্যে পদ্ধতির চেয়ে গৃহীত উত্তর

ক্যাভ্যাট : এটি কয়েক মিলিয়ন রেকর্ড সহ বড় ডেটাসেটের জন্য ধীর, তাই আপনি একটি limitধারা যোগ করতে চাইতে পারেন ।


4
"র্যান্ডম ()" স্ক্লাইটেও কাজ করে, সুতরাং আমরা যারা এখনও স্ক্লাইটে বিকাশ করছি এবং উত্পাদন পোস্টগ্র্রেস চালাচ্ছি তাদের ক্ষেত্রে আপনার সমাধান উভয় পরিবেশে কাজ করে।
উলিওং

5
আমি স্বীকৃত উত্তরের বিপরীতে এর জন্য একটি মানদণ্ড তৈরি করেছি । Postgresql 9.4 এ এই উত্তরটির পদ্ধতির দ্বিগুণ তত দ্রুত।
পানমারী


এটি দ্রুততম সমাধান
সেরজিও বেলভস্কিজ

1
"রেল 6.০-এ অ-অ্যাট্রিবিউট আর্গুমেন্ট নিষিদ্ধ করা হবে This এই পদ্ধতিটি ব্যবহারকারীর দ্বারা সরবরাহিত মান যেমন অনুরোধের প্যারামিটার বা মডেল বৈশিষ্ট্যগুলির সাথে কল করা উচিত নয় nown জ্ঞাত-নিরাপদ মানগুলি আরেল.এসকিএল () এ মোড়ানো দ্বারা পাস করা যেতে পারে" "
ট্রেন্টন টেলার 18

73

আপনার উদাহরণ কোডটি রেকর্ডগুলি মুছে ফেলার পরে ভুলভাবে আচরণ করা শুরু করবে (এটি নিম্ন আইডির সাথে আইটেমকে অন্যায়ভাবে পছন্দ করবে)

আপনি সম্ভবত আপনার ডাটাবেসের মধ্যে এলোমেলো পদ্ধতি ব্যবহার করে আরও ভাল। আপনি কোন ডিবি ব্যবহার করছেন তার উপর নির্ভর করে এগুলি পরিবর্তিত হয় তবে: অর্ডার => "RAND ()" mysql এর জন্য কাজ করে এবং: আদেশ => "RANDOM ()" পোস্টগ্রিজের জন্য কাজ করে

Model.first(:order => "RANDOM()") # postgres example

7
ডেটা বাড়ার সাথে সাথে মাইএসকিউএল-র র‌্যান্ড () এর অর্ডারটি ভয়াবহ রানটাইম শেষ হয়। এটি মাত্র কয়েক হাজার সারি থেকে শুরু করে (সময়ের প্রয়োজনীয়তার উপর নির্ভরশীল) অবিশ্বাস্য।
মাইকেল

মাইকেল একটি দুর্দান্ত পয়েন্ট সামনে এনেছে (এটি অন্যান্য ডিবিগুলির ক্ষেত্রেও সত্য)। সাধারণত বড় টেবিলগুলি থেকে এলোমেলো সারি নির্বাচন করা আপনি গতিশীল ক্রিয়ায় করতে চান এমন কিছু নয়। ক্যাচিং আপনার বন্ধু। আপনি যা সম্পাদন করতে চাইছেন তা পুনর্বিবেচনা করা কোনও খারাপ ধারণাও নাও হতে পারে।
সিমেন্টারিট

1
প্রায় দশ মিলিয়ন সারি সহ একটি টেবিলে মাইএসকিএলে আরএএনএন্ড () অর্ডার করা হল স্লোউইউউউউউউউউউউউউউ।
সাবিমেজে

24
আর কাজ করে না। Model.order("RANDOM()").firstপরিবর্তে ব্যবহার করুন।
ফিল পিরোজকভ

ধীর এবং ডাটাবেস নির্দিষ্ট। অ্যাক্টিভেকর্ডের ডেটাবেসগুলির মধ্যে নির্বিঘ্নে কাজ করার কথা রয়েছে তাই আপনার এই পদ্ধতিটি ব্যবহার করা উচিত নয়।
ডেক্স

29

মাইএসকিউএল 5.1.49, রুবি 1.9.2p180 + 5 মিলিয়ন রেকর্ড সহ পণ্য টেবিলে এই দুটি পদ্ধতির বেঞ্চমার্কিং:

def random1
  rand_id = rand(Product.count)
  rand_record = Product.first(:conditions => [ "id >= ?", rand_id])
end

def random2
  if (c = Product.count) != 0
    Product.find(:first, :offset =>rand(c))
  end
end

n = 10
Benchmark.bm(7) do |x|
  x.report("next id:") { n.times {|i| random1 } }
  x.report("offset:")  { n.times {|i| random2 } }
end


             user     system      total        real
next id:  0.040000   0.000000   0.040000 (  0.225149)
offset :  0.020000   0.000000   0.020000 ( 35.234383)

মাইএসকিউএলে অফসেটটি অনেক ধীর বলে মনে হচ্ছে।

সম্পাদনাও আমি চেষ্টা করেছিলাম

Product.first(:order => "RAND()")

তবে আমাকে এটি kill 60 সেকেন্ড পরে হত্যা করতে হয়েছিল। মাইএসকিউএল ছিল "ডিস্কে টেম্প টেবিলের অনুলিপি"। যে কাজ করে না।


1
যারা আরও পরীক্ষার সন্ধান করছেন তাদের জন্য সত্যিকারের এলোমেলো পদ্ধতির জন্য কতক্ষণ সময় লাগে: আমি Thing.order("RANDOM()").first250 টুকরো এন্ট্রি সহ একটি টেবিলে চেষ্টা করেছি - কোয়েরিটি অর্ধ সেকেন্ডের মধ্যে শেষ হয়েছে। (পোস্টগ্রিসকিউএল ৯.০, আরইই ১.৮..7, ২ এক্স ২.66 G গিগাহার্টজ কোর) যেহেতু আমি এককালীন "ক্লিনআপ" করছি me
ফ্লোরিয়ান পিলজ

6
রুবির র‌্যান্ড পদ্ধতিটি সেই নির্দিষ্ট সংখ্যার চেয়ে কম ফেরত দেয় যাতে আপনি চান rand_id = rand(Product.count) + 1বা আপনি কখনও শেষ রেকর্ডটি পাবেন না।
রিচি

4
random1আপনি যদি সারণীতে কোনও সারি মুছে ফেলেন তবে দ্রষ্টব্য কাজ করবে না। (গণনা সর্বোচ্চ আইডি থেকে কম হবে এবং আপনি উচ্চ আইডিসহ সারিগুলি নির্বাচন করতে পারবেন না)।
নিকোলাস

ব্যবহার random2একটি দ্বারা উন্নত করা যায় #orderএকটি সূচীবদ্ধ কলাম ব্যবহার করে।
কারসন রিঙ্ক

18

এটি এত কঠিন হতে হবে না।

ids = Model.pluck(:id)
random_model = Model.find(ids.sample)

pluckসারণীতে সমস্ত আইডির একটি অ্যারে প্রদান করে। sampleঅ্যারেতে থাকা পদ্ধতিটি অ্যারে থেকে একটি এলোমেলো আইডি প্রদান করে।

মুছে ফেলা সারিগুলির সাথে সারণীগুলির জন্য নির্বাচনের সমান সম্ভাবনা এবং সমর্থন সহ এটি ভাল সম্পাদন করা উচিত। এমনকি আপনি এটিকে বাধাগুলির সাথে মিশ্রিত করতে পারেন।

User.where(favorite_day: "Friday").pluck(:id)

এবং এর মাধ্যমে এমন কোনও র্যান্ডম ব্যবহারকারী চয়ন করুন যিনি কেবল কোনও ব্যবহারকারীর চেয়ে শুক্রবার পছন্দ করেন।


8
এটি পরিষ্কার এবং একটি ছোট টেবিল বা এককালীন ব্যবহারের জন্য কাজ করে, কেবল নোট করুন এটি মাপবে না। একটি 3 এম টেবিলে, প্ল্যাকিং আইডিগুলি মারিয়াডিবিতে আমার 15 সেকেন্ড সময় নেয়।
মাহমোফ

2
এটা একটা ভাল দিক. একই গুণাবলী বজায় রেখে আপনি কী দ্রুত বিকল্প সমাধান খুঁজে পেয়েছেন?
নীলস বি

গৃহীত অফসেট সমাধান একই গুণাবলী বজায় রাখে না?
মাহেমফ

না, এটি শর্তাদি সমর্থন করে না এবং মুছে ফেলা রেকর্ড সহ টেবিলগুলির জন্য নির্বাচনের সমান সম্ভাবনাও রাখে না।
নীলস বি

1
এটি ভাবতে আসুন, আপনি যদি অফসেট দিয়ে গণনা এবং নির্বাচন উভয়ই সীমাবদ্ধতাগুলি প্রয়োগ করেন তবে কৌশলটি কাজ করা উচিত। আমি কেবল গণিতে এটি প্রয়োগ করার কথা ভাবছিলাম।
নীলস বি

15

এটা তোলে না করাই ভালো যে আপনি এই সমাধান ব্যবহার করেন, কিন্তু যদি কোনো কারণে আপনি সত্যিই এলোমেলোভাবে একটি রেকর্ড নির্বাচন করতে চান যখন শুধুমাত্র একটি ডাটাবেসের কোয়েরি উপার্জন, আপনি ব্যবহার করতে পারে sampleপদ্ধতি থেকে রুবি এরে বর্গ , যা আপনি একটি র্যান্ডম আইটেম নির্বাচন করতে পারবেন একটি অ্যারে থেকে

Model.all.sample

এই পদ্ধতি শুধুমাত্র ডাটাবেসের কোয়েরি প্রয়োজন, কিন্তু এটা উল্লেখযোগ্যভাবে ধীর বিকল্প চেয়ে মত Model.offset(rand(Model.count)).firstযা দুই ডাটাবেসের প্রশ্নের প্রয়োজন যদিও সাম্প্রতিক এখনো পছন্দ করা হয়।


99
এটা করো না. কখনো।
জাবাবা

5
আপনার যদি আপনার ডাটাবেসে 100k সারি থাকে তবে এগুলি সমস্তই মেমরিতে লোড করতে হবে।
ভেঙ্কট ডি

3
অবশ্যই এটি উত্পাদন রিয়েলটাইম কোডের জন্য প্রস্তাবিত নয়, তবে আমি এই সমাধানটি পছন্দ করি, এটি জাল মান সহ ডেটাবেস বীজের মতো বিশেষ পরিস্থিতিতে ব্যবহার করা খুব স্পষ্ট ।
fguillen

13
দয়া করে - কখনও বলবেন না। টেবিলটি ছোট হলে এটি ডেভলপমেন্ট-টাইম ডিবাগিংয়ের জন্য দুর্দান্ত সমাধান। (এবং আপনি যদি নমুনা নিচ্ছেন তবে ডিবাগিং সম্ভবত ব্যবহারের ক্ষেত্রে)।
মাহেমফ

আমি বপন জন্য ব্যবহার করছি এবং আমার জন্য ভাল। তদ্ব্যতীত, Model.all.sample (n) খুব বেশি কাজ করে :)
Ignacio Gaspar Véjar

13

আমি এটি পরিচালনা করতে একটি রেল 3 রত্ন তৈরি করেছি:

https://github.com/spilliton/randumb

এটি আপনাকে এই জাতীয় জিনিসগুলি করতে দেয়:

Model.where(:column => "value").random(10)

7
এই রত্নটিরORDER BY RANDOM()RAND() ডকুমেন্টেশনে তারা ব্যাখ্যা করে "এলোমেলোভাবে কেবল আপনার প্রশ্নের জন্য অতিরিক্ত (বা মাইএসকিএল জন্য) পরীক্ষা করে।" - অতএব, @ সিমেন্টার্টের উত্তরের মন্তব্যে উল্লিখিত খারাপ পারফরম্যান্স সম্পর্কিত মন্তব্যগুলিও এই রত্নটি ব্যবহার করার সময় প্রয়োগ হয়। তবে কমপক্ষে এটি ডিবি স্বাধীন।
নিকোলাস

8

কনসোল থেকে আমি এটি প্রায়শই ব্যবহার করি আমি একটি ইনিশিয়ালাইজারে অ্যাক্টিভেকর্ডটি প্রসারিত করি - রেলস 4 উদাহরণ:

class ActiveRecord::Base
  def self.random
    self.limit(1).offset(rand(self.count)).first
  end
end

আমি তখন Foo.randomএলোমেলো রেকর্ড ফিরিয়ে আনার জন্য কল করতে পারি।


1
তোমার কি দরকার limit(1)? ActiveRecord#firstএটি করার জন্য যথেষ্ট স্মার্ট হওয়া উচিত।
টোকল্যান্ড

6

পোস্টগ্রিসে একটি প্রশ্ন:

User.order('RANDOM()').limit(3).to_sql # Postgres example
=> "SELECT "users".* FROM "users" ORDER BY RANDOM() LIMIT 3"

অফসেট ব্যবহার করে, দুটি ক্যোয়ারী:

offset = rand(User.count) # returns an integer between 0 and (User.count - 1)
Model.offset(offset).limit(1)

1
-1 এর প্রয়োজন নেই,
র‌্যাণ্ড

ধন্যবাদ, পরিবর্তিত: +1:
টমাস ক্লেম

5

এগুলি পড়লে আমার খুব বেশি আত্মবিশ্বাস হয়নি যে এইগুলির মধ্যে কোনটি আমার বিশেষ পরিস্থিতিতে রেজেল ৫ এবং মাইএসকিউএল / মারিয়া ৫.৫ নিয়ে সবচেয়ে ভাল কাজ করবে। সুতরাং আমি 000 65000 রেকর্ডে উত্তরগুলির কয়েকটি পরীক্ষা করেছি এবং দুটিতে অ্যাওয়ে নেওয়া হয়েছে:

  1. RAND () এর সাথে limitএকটি পরিষ্কার বিজয়ী।
  2. ব্যবহার করবেন না pluck+ + sample
def random1
  Model.find(rand((Model.last.id + 1)))
end

def random2
  Model.order("RAND()").limit(1)
end

def random3
  Model.pluck(:id).sample
end

n = 100
Benchmark.bm(7) do |x|
  x.report("find:")    { n.times {|i| random1 } }
  x.report("order:")   { n.times {|i| random2 } }
  x.report("pluck:")   { n.times {|i| random3 } }
end

              user     system      total        real
find:     0.090000   0.000000   0.090000 (  0.127585)
order:    0.000000   0.000000   0.000000 (  0.002095)
pluck:    6.150000   0.000000   6.150000 (  8.292074)

এই উত্তরটি মোহাম্মদের উত্তর সংশ্লেষিত করে, যাচাই করে এবং আপডেট করে, একই সাথে নাম ওয়াং এর একই মন্তব্য এবং স্বীকৃত উত্তরে ফ্লোরিয়ান পিলজের মন্তব্য - দয়া করে তাদের কাছে ভোট প্রেরণ করুন!


3

আপনি ব্যবহার করতে পারেন Arrayপদ্ধতি sampleপদ্ধতি, sample, একটি অ্যারে থেকে একটি র্যান্ডম বস্তুর ফেরৎ যাতে এটা আপনি শুধুমাত্র একটি সহজ মধ্যে Exec প্রয়োজন ব্যবহার করার জন্য ActiveRecordযে ক্যোয়ারির কারণে একটি সংগ্রহ আসতে, উদাহরণস্বরূপ:

User.all.sample

এরকম কিছু ফিরে আসবে:

#<User id: 25, name: "John Doe", email: "admin@example.info", created_at: "2018-04-16 19:31:12", updated_at: "2018-04-16 19:31:12">

আমি এআর ব্যবহার করার সময় অ্যারে পদ্ধতিগুলির সাথে কাজ করার পরামর্শ দেব না। এই পথে order('rand()').limit(1)"একই" কাজ করতে ( প্রায় 10 ডলার রেকর্ড সহ) প্রায় 8 বার সময় লাগে।
সেবাস্তিয়ান পালমা

3

এলোমেলো রেকর্ডগুলির জন্য এই রত্নটিকে দৃ St়ভাবে সুপারিশ করুন, যা প্রচুর ডেটা সারি সহ টেবিলের জন্য বিশেষভাবে ডিজাইন করা হয়েছে:

https://github.com/haopingfan/quick_random_records

এই মণি ব্যতীত অন্য সমস্ত উত্তর বড় ডেটাবেস সহ খারাপভাবে সম্পাদন করে:

  1. quick_random_records কেবল 4.6msসম্পূর্ণ ব্যয় ।

এখানে চিত্র বর্ণনা লিখুন

  1. User.order('RAND()').limit(10)খরচ 733.0ms

এখানে চিত্র বর্ণনা লিখুন

  1. গৃহীত উত্তর offsetপদ্ধতির 245.4msসম্পূর্ণরূপে ব্যয় ।

এখানে চিত্র বর্ণনা লিখুন

  1. User.all.sample(10)পদ্ধতির খরচ 573.4ms

এখানে চিত্র বর্ণনা লিখুন


দ্রষ্টব্য: আমার টেবিলটিতে কেবল 120,000 জন ব্যবহারকারী রয়েছে। আপনার যত বেশি রেকর্ড রয়েছে, পারফরম্যান্সের পার্থক্য তত বেশি হবে।


2

যদি আপনাকে নির্দিষ্ট সুযোগের মধ্যে কিছু এলোমেলো ফলাফল নির্বাচন করতে হয় :

scope :male_names, -> { where(sex: 'm') }
number_of_results = 10

rand = Names.male_names.pluck(:id).sample(number_of_results)
Names.where(id: rand)

1

কোনও তালিকা থেকে এলোমেলোভাবে বাছাইয়ের রুবি পদ্ধতিটি samplesampleঅ্যাক্টিভেকর্ডের জন্য একটি দক্ষ তৈরি করতে চাই এবং পূর্ববর্তী উত্তরের উপর ভিত্তি করে আমি ব্যবহার করেছি:

module ActiveRecord
  class Base
    def self.sample
      offset(rand(size)).first
    end
  end
end

আমি এটি put lib/ext/sample.rbোকাই এবং তারপরে এটি দিয়ে লোড করুন config/initializers/monkey_patches.rb:

Dir[Rails.root.join('lib/ext/*.rb')].each { |file| require file }

এটি যদি একটি মডেল আকার ইতিমধ্যে ক্যাশে করা হয় এবং অন্যথায় দুটি জিজ্ঞাসা করা হবে।


1

4.2 রেল এবং ওরাকল :

ওরাকলের জন্য আপনি আপনার মডেলটিতে এমন সুযোগ তৈরি করতে পারেন:

scope :random_order, -> {order('DBMS_RANDOM.RANDOM')}

অথবা

scope :random_order, -> {order('DBMS_RANDOM.VALUE')}

এবং তারপরে একটি নমুনার জন্য এটিকে কল করুন:

Model.random_order.take(10)

অথবা

Model.random_order.limit(5)

অবশ্যই আপনি এর মতো সুযোগ ছাড়াই অর্ডারও দিতে পারেন:

Model.all.order('DBMS_RANDOM.RANDOM') # or DBMS_RANDOM.VALUE respectively

আপনি পোস্টগ্র্রেস সহ order('random()'এবং মাইএসকিউএল order('rand()')পাশাপাশি এটি করতে পারেন। এটি অবশ্যই সেরা উত্তর।
জ্রোচাইন্ড

1

মাইএসকিউএল ডাটাবেসের জন্য চেষ্টা করুন: মডেল.অর্ডার ("RAND ()") first


এটি মাইএসকিএলে কাজ করে না .. আপনার কমপক্ষে ডিবি ইঞ্জিনটি কী কাজ করবেন তা অনুমান করা উচিত
আর্নল্ড রোা

দুঃখিত, টাইপো ছিল। এখনই স্থির। মাইএসকিএল (কেবল) এর জন্য কাজ করা উচিত
ভাদিম এরিমিয়েভ

1

আপনি যদি PostgreSQL 9.5+ ব্যবহার করেন তবে আপনি TABLESAMPLEএলোমেলো রেকর্ড নির্বাচন করতে সুবিধা নিতে পারেন ।

দুটি ডিফল্ট নমুনা পদ্ধতি ( SYSTEMএবং BERNOULLI) আপনার সারণীতে মোট সারিগুলির সংখ্যার শতাংশ হিসাবে ফিরে আসার জন্য সারিগুলির সংখ্যা নির্দিষ্ট করে require

-- Fetch 10% of the rows in the customers table.
SELECT * FROM customers TABLESAMPLE BERNOULLI(10);

এর জন্য উপযুক্ত শতাংশ বাছাই করতে সারণীতে রেকর্ডের পরিমাণ জেনে রাখা দরকার, এটি দ্রুত খুঁজে পাওয়া সহজ নাও হতে পারে। ভাগ্যক্রমে, এমন একটি tsm_system_rowsমডিউল রয়েছে যা আপনাকে সরাসরি ফিরতে সারিগুলির সংখ্যা নির্দিষ্ট করতে দেয়।

CREATE EXTENSION tsm_system_rows;

-- Fetch a single row from the customers table.
SELECT * FROM customers TABLESAMPLE SYSTEM_ROWS(1);

অ্যাক্টিভেকর্ডের মধ্যে এটি ব্যবহার করতে, প্রথমে মাইগ্রেশনের মধ্যে এক্সটেনশন সক্ষম করুন:

class EnableTsmSystemRowsExtension < ActiveRecord::Migration[5.0]
  def change
    enable_extension "tsm_system_rows"
  end
end

তারপরে fromকোয়েরির ধারাটি সংশোধন করুন :

customer = Customer.from("customers TABLESAMPLE SYSTEM_ROWS(1)").first

আমি জানি না যে SYSTEM_ROWSস্যাম্পলিংয়ের পদ্ধতিটি পুরোপুরি এলোমেলো হবে বা এটি কেবল এলোমেলো পৃষ্ঠা থেকে প্রথম সারিতে ফিরে আসে কিনা।

এই তথ্যগুলির বেশিরভাগই গুলসিন ইল্ডিরিমের লেখা ২ য় কুইক্রেড ব্লগ পোস্ট থেকে নেওয়া হয়েছিল ।


1

এতগুলি উত্তর দেখার পরে আমি সেগুলি আমার পোস্টগ্রিজএসকিউএল (9.6.3) ডাটাবেসে বেনমার্ক করার সিদ্ধান্ত নিয়েছি। আমি আরও ছোট 100,000 টেবিল ব্যবহার করেছি এবং মডেল.অর্ডার ("RANDOM ()") থেকে মুক্তি পেয়েছি first

হ্যান্ড ডাউন উইনডারের 10 কলামের সাথে 2,500,000 এন্ট্রি সহ একটি টেবিল ব্যবহার করা ছিল রানার আপের তুলনায় প্লাক পদ্ধতিটি প্রায় 8 গুণ বেশি দ্রুত ছিল (অফসেট I আমি কেবল এটি একটি স্থানীয় সার্ভারে চালিয়েছিলাম যাতে সংখ্যাটি স্ফীত হতে পারে তবে এটি যথেষ্ট বড় ছিল পদ্ধতিটি আমি কী ব্যবহার করে শেষ করব It's এটি লক্ষণীয় যে এটির কারণগুলির কারণ হতে পারে আপনি একবারে 1 টিরও বেশি ফলাফল এড়াতে পারবেন কারণ সেগুলির প্রতিটিরই অনন্য অরফ কম এলোমেলো হবে।

আমার 25,000,000 সারি টেবিলটিতে 100 বার চলমান প্লাক জিতেছে সম্পাদনা: আসলে এই সময়টিতে লুপটি অন্তর্ভুক্ত করা হয় যদি আমি এটি বের করি তবে এটি আইডিটিতে প্রায় সরল পুনরাবৃত্তি হিসাবে প্রায় দ্রুত চলে। যাহোক; এটি মোটামুটি পরিমাণ র‍্যাম গ্রহণ করে।

RandomModel                 user     system      total        real
Model.find_by(id: i)       0.050000   0.010000   0.060000 (  0.059878)
Model.offset(rand(offset)) 0.030000   0.000000   0.030000 ( 55.282410)
Model.find(ids.sample)     6.450000   0.050000   6.500000 (  7.902458)

এলোমেলোভাবে রায় দেওয়ার জন্য আমার 100,000 সারি টেবিলের উপরে 2000 গুণ থাকা ডেটা এখানে

RandomModel       user     system      total        real
find_by:iterate  0.010000   0.000000   0.010000 (  0.006973)
offset           0.000000   0.000000   0.000000 (  0.132614)
"RANDOM()"       0.000000   0.000000   0.000000 ( 24.645371)
pluck            0.110000   0.020000   0.130000 (  0.175932)

1

খুব পুরানো প্রশ্ন কিন্তু সাথে:

rand_record = Model.all.shuffle

আপনি রেকর্ডের একটি অ্যারে পেয়েছেন, এলোমেলো অর্ডার অনুসারে বাছাই করেছেন। রত্ন বা স্ক্রিপ্টের দরকার নেই।

আপনি যদি একটি রেকর্ড চান:

rand_record = Model.all.shuffle.first

1
সেরা বিকল্প নয়, কারণ এটি সমস্ত রেকর্ডকে মেমরিতে লোড করে। এছাড়াও, shuffle.first==.sample
অ্যান্ড্রু রোজেনকো

0

আমি আরআর এর জন্য একেবারে নতুন কিন্তু আমার পক্ষে এটি কাজ করার জন্য পেয়েছি:

 def random
    @cards = Card.all.sort_by { rand }
 end

এটি থেকে এসেছে:

রুবিতে এলোমেলোভাবে কীভাবে একটি অ্যারে বাছাই করা (স্ক্যাম্বল করা)?


4
এটি সম্পর্কে খারাপ জিনিস এটি ডাটাবেস থেকে সমস্ত কার্ড লোড করতে চলেছে। এটি ডাটাবেসের ভিতরে করা আরও দক্ষ।
আন্তন কুজমিন

এছাড়াও আপনি অ্যারে পরিবর্তন করতে পারেন array.shuffle। যাইহোক, সাবধান, Card.allসমস্ত কার্ডের রেকর্ডগুলি মেমরিতে লোড করবে, যা আমরা আরও বেশি অবজেক্টের বিষয়ে কথা বলছি।
থমাস ক্লেম

0

কি করতে হবে:

rand_record = Model.find(Model.pluck(:id).sample)

আমার জন্য অনেক পরিষ্কার


0

আমি আমার অ্যাপে স্যামের এই উদাহরণটি বেঞ্চমার্কের রেল ৪.২.৮ ব্যবহার করে চেষ্টা করেছি (আমি র্যান্ডমটির জন্য ১. শ্রেণিবদ্ধ। গণনা করি, কারণ যদি এলোমেলোভাবে একটি 0 লাগে তবে এটি একটি ত্রুটি তৈরি করবে (অ্যাক্টিভেকর্ড :: রেকর্ডনোটফাউন্ড: সন্ধান করতে পারেনি 'আইডি' = 0) সহ বিভাগ এবং খনিটি ছিল:

 def random1
2.4.1 :071?>   Category.find(rand(1..Category.count))
2.4.1 :072?>   end
 => :random1
2.4.1 :073 > def random2
2.4.1 :074?>    Category.offset(rand(1..Category.count))
2.4.1 :075?>   end
 => :random2
2.4.1 :076 > def random3
2.4.1 :077?>   Category.offset(rand(1..Category.count)).limit(rand(1..3))
2.4.1 :078?>   end
 => :random3
2.4.1 :079 > def random4
2.4.1 :080?>    Category.pluck(rand(1..Category.count))
2.4.1 :081?>
2.4.1 :082 >     end
 => :random4
2.4.1 :083 > n = 100
 => 100
2.4.1 :084 > Benchmark.bm(7) do |x|
2.4.1 :085 >     x.report("find") { n.times {|i| random1 } }
2.4.1 :086?>   x.report("offset") { n.times {|i| random2 } }
2.4.1 :087?>   x.report("offset_limit") { n.times {|i| random3 } }
2.4.1 :088?>   x.report("pluck") { n.times {|i| random4 } }
2.4.1 :089?>   end

                  user      system      total     real
find            0.070000   0.010000   0.080000 (0.118553)
offset          0.040000   0.010000   0.050000 (0.059276)
offset_limit    0.050000   0.000000   0.050000 (0.060849)
pluck           0.070000   0.020000   0.090000 (0.099065)

0

.order('RANDOM()').limit(limit)ঝরঝরে দেখায় তবে বড় টেবিলগুলির জন্য ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে এটি limit1 নম্বর (অভ্যন্তরীণভাবে ডাটাবেসে তবে রেলের মধ্যে নয়) থাকা সারিগুলি সরিয়ে ফেলতে হবে । আমি মাইএসকিউএল সম্পর্কে নিশ্চিত নই তবে পোস্টগ্রিসে এটি ঘটে। এখানে এবং এখানে আরও ব্যাখ্যা ।

বড় টেবিলের জন্য ওয়ান সমাধান .from("products TABLESAMPLE SYSTEM(0.5)")যেখানে 0.5উপায়ে 0.5%। তবে, আমি দেখতে পাই যে এই সমাধানটি এখনও ধীর গতিতে রয়েছে যদি আপনার এমন WHEREশর্ত থাকে যা প্রচুর সারিগুলিকে ফিল্টার করে। আমার ধারণা এটি কারণ কারণ শর্ত প্রয়োগের TABLESAMPLE SYSTEM(0.5)আগে সমস্ত সারি আনুন WHERE

বড় টেবিলগুলির জন্য আরেকটি সমাধান (তবে খুব এলোমেলো নয়):

products_scope.limit(sample_size).sample(limit)

যেখানে sample_sizeহতে পারে 100(তবে খুব বেশি বড় নয় অন্যথায় এটি ধীর হয় এবং প্রচুর স্মৃতি গ্রহণ করে), এবং limitহতে পারে 1। দ্রষ্টব্য যে যদিও এটি দ্রুত তবে এটি সত্যিই এলোমেলো নয়, এটি sample_sizeকেবল রেকর্ডের মধ্যে এলোমেলো ।

পিএস: উপরের উত্তরের বেনমার্কের ফলাফল নির্ভরযোগ্য নয় (কমপক্ষে পোস্টগ্র্রেসে) কারণ ডিবি ক্যাশে ধন্যবাদ 2 র্থ সময়ে চলমান কিছু ডিবি ক্যোয়ারী প্রথমবারের চেয়ে চলমান তুলনায় দ্রুততর হতে পারে। এবং দুর্ভাগ্যক্রমে এই বেঞ্চমার্কগুলিকে নির্ভরযোগ্য করে তোলার জন্য পোস্টগ্র্রেসে ক্যাশে অক্ষম করার কোনও সহজ উপায় নেই।


0

ব্যবহারের পাশাপাশি RANDOM(), আপনি এটিকে একটি সুযোগেও ফেলে দিতে পারেন:

class Thing
  scope :random, -> (limit = 1) {
    order('RANDOM()').
    limit(limit)
  }
end

বা, যদি আপনি এটিকে সুযোগ হিসাবে কল্পনা করেন না, কেবল এটি একটি শ্রেণিবদ্ধ পদ্ধতিতে ফেলে দিন। এখন Thing.randomপাশাপাশি কাজ করে Thing.random(n)


0

"এলোমেলো" এর অর্থ এবং আপনি আসলে কী করতে চান তার উপর নির্ভর করে, take যথেষ্ট হতে পারে।

এলোমেলো "অর্থ" দ্বারা আমি বোঝাতে চাইছি:

  • আপনি কি আমাকে বোঝাতে চান এমন কোনও উপাদান দিন যা আমি তার অবস্থানের বিষয়ে চিন্তা করি না? তাহলেই যথেষ্ট।
  • এখন, আপনি যদি বোঝাতে চান যে "আমাকে ন্যায্য সম্ভাবনার সাথে এমন কোনও উপাদান দিন যা বারবার পরীক্ষা-নিরীক্ষা আমাকে সেট থেকে বিভিন্ন উপাদান দেয়", তবে অন্যান্য উত্তরে উল্লিখিত যে কোনও পদ্ধতিতে "ভাগ্যকে" বাধ্য করুন।

উদাহরণস্বরূপ, পরীক্ষার জন্য, নমুনা ডেটা যাইহোক এলোমেলোভাবে তৈরি করা যেতে পারে, তাই যথেষ্টের takeচেয়ে বেশি এবং সত্যই বলা যায় first

https://guides.rubyonrails.org/active_record_querying.html#take

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.