PDA

View Full Version : تخصیص ۱۰۰ عدد به هر کاربر با کاربران به تعداد ۵۰۰ کاربر



H:Shojaei
چهارشنبه 08 مهر 1394, 17:44 عصر
سلام...
فرض کنید ۵۰۰ کاربر داریم و این ۵۰۰ کاربر هرکدوم به تعداد مشخصی امتیاز دارن مثلا یکی ۱ امتیاز یکی ۱۰ امتیاز و یکی ۵۰۰ امتیاز...
حالا میخوایم به این کاربرا هرکدوم به تعداد امتیازی که دارن بهشون عدد ثابت بدم مثلا کسی که ۵۰۰ امتیاز داره ۵۰۰ عدد باید داشته باشه و کسی که ۱۰ امتیاز ۱۰ عدد بهش بدم اعداد تو یه رنج نیستن که بگم از ۱ تا مثلا ۵۰۰ و کلا تک تک اعداد به صورت تصادفی به کاربرا داده میشن...
این اعداد واسه این به کاربر داده میشه که قراره قرعه کشی آنلاین انجام بشه و از بین این ۵۱۱ عدد ۱ عدد انتخاب میشه و کسی که اون عدد رو داره برنده اعلام میشه...

حالا فرض کنید ۵۰۰ کاربر داشته باشیم که هرکدوم ۱۰۰ امتیاز دارن! حالا اگر بخوایم به تعداد امتیاز هر نفر عدد بهش بدیم میشه ۵۰,۰۰۰ عدد که باید تو دیتابیس ذخیره بشه! و این تعداد یکجا تو کرون جاب محاسبه میشه و واسه کاربران تو یه جدول درج میشه...
سوالم اینه که
۱- راه حل بهتری به ذهن شما نمیرسه واسه بهینه سازی کل این مسئله!؟
۲- اگر راه دیگه نتونم پیدا کنم این تعداد ۵۰۰۰۰ کوئری درج مشکلی نداره یک جا قراره انجام بشه و با توجه به این که این عملیات هر روز تو یه ساعت مشخص انجام میشه!؟

opluse
چهارشنبه 08 مهر 1394, 18:06 عصر
سلام اگه من بودم اینجوری کار میکردم

علی 20 امتیاز
احمد 50 امتیاز
حمید 40 امتیاز
ناصر 10 امتیاز

خوب حالا جموع امتیازات میشه 120

حالا یک عدد رندوم از 1 تا 120 انتخاب میشه که همون قرعه کشی هست در واقع

حالا مثلا عدد 83 بصورت رندوم انتخاب شده !

خوب حالا این 83 ماله کیه ؟؟؟؟؟؟

اول میایم ترتیب یوزرها رو بهم میریزیم

احمد 50 امتیاز
علی 20 امتیاز
ناصر 10 امتیاز
حمید 40 امتیاز

حالا شماره 1 تا 50 ماله احمد
شماره 51 تا 70 ماله علی
شماره 71 تا 80 ماله ناصر
شماره 81 تا 120 هم ماله حمید

پس حمید توی قرعه کشی برنده شده بهش تبریک میگم خخخ

البته خودت استادی ولی اگه خواستی بگو شب نمونه کدشو بنویسم .

us1234
چهارشنبه 08 مهر 1394, 19:35 عصر
در خصوص تابع توزیع چگالی احتمال تحقیق کردید ؟

به یک استاد آمار و احتمال مراجعه کنید .

روشی که قبلا در تاپیک مشابه شما (http://barnamenevis.org/showthread.php?506707-%D8%B3%DB%8C%D8%B3%D8%AA%D9%85-%D9%82%D8%B1%D8%B9%D9%87-%DA%A9%D8%B4%DB%8C-%D8%A8%D8%A7-%D8%A7%D8%AD%D8%AA%D8%B3%D8%A7%D8%A8-%D8%A7%D9%85%D8%AA%DB%8C%D8%A7%D8%B2%D8%A7%D8%AA-%D9%87%D8%B1-%DA%A9%D8%A7%D8%B1%D8%A8%D8%B1)گفتم جواب میدهد ولی اصولی نیست و عملا دارد منابع سیستم را هدر میدهد .

H:Shojaei
چهارشنبه 08 مهر 1394, 20:52 عصر
ممنون دوستان از هر دو روش اطلاع دارم و پیاده سازی کردم اولی که همون انتخاب تصادفی هست دومی هم که تابع چگالی هست و خیلی هم کاربردی تر استفاده کردم...
ولی روشی که من میخوام انجام بدم واسه اینه که کاربرا تو قرعه کشی دست داشته باشن در حقیقت هر کاربر واسه ما یک عدد میفرسته که این اعداد نفر برنده رو تشکیل میدن... یعنی نه به وسیله توزیع چگالی نه به صورت تصادفی کاربر نمیتونه انتخاب بشه...
سیستمی که توضیح دادم lottery هایی هست که الآن بابه تو خارج ولی پیاده سازیش و اون اعداد گنده دردسر شده! به نوعی همین سیستم رو میخوام به هر روشی شده بهینش کنم...
راستی نگفتید این 50000 به نظر شما درسته که مثلا در یک زمان این مقدار رکورد درج بشه!؟

us1234
پنج شنبه 09 مهر 1394, 08:27 صبح
به نظر من برای هر کاربر یک فیلد دیگه مثل همان امتیاز در نظر بگیر و اعداد هر شخص را به صورت serialize شده نگهداری کن

از نظر ذخیره سازی بهینه تر است ولی در تشخیص برنده یکم پروسه شناسایی سختر میشود ( باید برای تک تک کاربران شماره هارا unserialize کنید و بعد چک کنید ببیند عدد برنده داخل اعداد کاربر هست یا خیر )
ولی اگر به هر کاربر به میزان امتیازش یک بازه تعلق میگرفت کار خیلی ساده بود و نیاز نبود کل اعداد ذخیره شود .

مثلا کاربر 500 امتیازی از 0 تا 499 بازه اش است و اگر عدد انتخابی داخل این بازه بود مسلماً این کاربر برنده شده است ...

H:Shojaei
پنج شنبه 09 مهر 1394, 10:18 صبح
به نظر من برای هر کاربر یک فیلد دیگه مثل همان امتیاز در نظر بگیر و اعداد هر شخص را به صورت serialize شده نگهداری کن

از نظر ذخیره سازی بهینه تر است ولی در تشخیص برنده یکم پروسه شناسایی سختر میشود ( باید برای تک تک کاربران شماره هارا unserialize کنید و بعد چک کنید ببیند عدد برنده داخل اعداد کاربر هست یا خیر )
ولی اگر به هر کاربر به میزان امتیازش یک بازه تعلق میگرفت کار خیلی ساده بود و نیاز نبود کل اعداد ذخیره شود .

این هم خوبه ولی باید روش تحقیق کنم ولی باز هم دنبال روش بهتری هستم که بشه جایگزین کرد که بهینه باشه...
اگر روش خوبی پیدا کنم واسه این موردش یه سیستم قرعه کشی آنلاین که تقریبا بی نقص باشه ازش در میاد و اسکریپتش رو اگر بتونم مینویسم و میگذارم واسه عموم...


مثلا کاربر 500 امتیازی از 0 تا 499 بازه اش است و اگر عدد انتخابی داخل این بازه بود مسلماً این کاربر برنده شده است ...
درسته ولی مسئله اینجاست که اینطوری اولا کاربرا اطمینان کمتری میکنن به قرعه کشی(بالاخره هست چنین مواردی)...
دوما این که ما گفتیم تو این تعداد کاربر چندین برنده داشته باشیم که خود کاربرا تعیین میکنن چند تا باشه... مثلا ممکنه تو ۵۰۰ کاربر ۱۰۰ برنده داشته باشه و بنابراین نفر اول که مشخص میشه نفرات بعد شماره نفر اول -- یا ++ میشه تا اونها هم مشخص بشن...
و سوم هم این که بازه به هیچ وجه نداریم اعدادی که به کاربرا داده میشن بر حسب فاکتوریل محاسبه میشه و پشت سر هم نیستن به این صورت که مثلا اگر ۵۰۰ امتیاز باشه و ۵۰۰ عدد بخوایم فاکتوریل 5 استفاده میشه یعنی اعداد 0 تا 5 رو میشه به نحوی کنار هم قرار داد که ۷۲۰ نوع مختلف عدد داشته باشیم بدون این که یک عدد تکراری باشه تو هر کدومشون و هر کدوم رو به یک کاربر میدیم...
پس این که بگیم ۰-۱۰ واسه یه کاربر اصلا همچین چیزی نداریم...

H:Shojaei
پنج شنبه 09 مهر 1394, 10:31 صبح
البته الآن که فکر میکنم میبینم با serialize میشه یه کارایی کرد...
چون من وقتی میخوام یک عدد رو به عنوان برنده اعلام کنم اول باید ببینم این عدد متعلق به کسی هست یا نه حالا به صورت آرایه اعدادی که به هر کاربر تخصیص داده میشه رو ذخیره کنیم و عددی که به عنوان برنده در میاد رو توی فیلد سریالایز شده جستجو کنیم... به این صورت مشخص میشه که کدوم کاربر این عدد رو داره و همچنین موقعی که میخواد برنده اعلام بشه این عدد جستجو میشه و کاربری که این عدد رو داشته باشه اعلام میشه...
ولی باز یک ایرادی که میتونه داشته باشه واسه این که یک عدد وقتی در میاد ببینیم کسی اون رو داره باید یک select بزنیم بین داده های سریالایز شده و اگر عدد واسه کاربری نبود باز یه عدد دیگه و... که در بدترین حالت برای ۵۰۰ امتیاز ۲۲۰ عدد داریم که به کاربری تعلق نگرفته و ۲۲۰ کوئری select باید زده بشه!! و حالا اگر اعداد ۷۲۱ باشه باید از فاکتوریل ۶ استفاده بشه که بدترین حالتش میشه تقریبا ۴۳۰۰ عدد که به هیچ کس تعلق نداره و به این تعداد select!!!
که واسه حل این باز میشه اول همه اعداد همه کاربرا رو گرفت همه رو unserialize کرد و تو آرایه php جستجو کرد اینطوری بهتر میشه...

به این صورت روش چطوره به نظر شما!؟

us1234
پنج شنبه 09 مهر 1394, 10:57 صبح
البته الان یکم فکر کردم ، نیاز به unserialize نیست .
به صورت json ذخیره کن و بعد داخل رشته مربوطه select کن
شما یک آرایه خواهید داشت به فرمت json مثل زیر :


["1","2","3","4"]

فقط باید LIKE ساده بزنید :

SELECT id FROM.... WHERE `num` LIKE '%"1",%'

H:Shojaei
پنج شنبه 09 مهر 1394, 11:07 صبح
البته الان یکم فکر کردم ، نیاز به unserialize نیست .
به صورت json ذخیره کن و بعد داخل رشته مربوطه select کن
شما یک آرایه خواهید داشت به فرمت json مثل زیر :


["1","2","3","4"]

فقط باید LIKE ساده بزنید :

SELECT id FROM.... WHERE `num` LIKE '%"1",%'
آره تو پست قبلی دقیقا به همین رسیدم ولی به جیسونش فکر نکرده بودم اینطوری بهتره...
و حتی میشه به جای like گرفتن اول رکورد ها رو بگیرم و بعد preg_match بزنم...
فکر میکنم همین راه فعلا بهترین باشه دیگه...

us1234
پنج شنبه 09 مهر 1394, 16:22 عصر
آره تو پست قبلی دقیقا به همین رسیدم ولی به جیسونش فکر نکرده بودم اینطوری بهتره...
و حتی میشه به جای like گرفتن اول رکورد ها رو بگیرم و بعد preg_match بزنم...
فکر میکنم همین راه فعلا بهترین باشه دیگه...

دستورات سمت mySql به دلیل هسته قدرتمند mySql سریع تر هستند ، پس نیاز نیست کل رکورد ها بیاری داخل php و بعد چک کنی .
به نظر من LIKE ارجعیت دارد با preg_match داخل php .
در ضمن در سلکت mySql هم میتوانید از Regular Expressions استفاده کنید ...

H:Shojaei
پنج شنبه 09 مهر 1394, 16:56 عصر
همه اینا درسته ولی تو قرعه کشی وقتی عددی که در میاد اگر به هیچ کاربری تخصیص داده نشده باشه در بدترین حالت سه میلیون و سی صد هزار بار باید قرعه کشی تکرار بشه و این یعنی سه میلیون و سیصد هزار چک کردن دیتابیس!!
و این که preg_match رو هم باهاش این کار رو نمیشد انجام داد (درد سر زیاد داشت) بنابراین کل json ها رو گرفتم و دیکد کردم ازش یک آرایه به دست اومد و توی اون آرایه سمت php با in_array چک میکنم که عددی که درمیاد واسه کاربری ثبت شده یا نه...
به نظر شما حالا کدوم بهتره LIKE یا in_array...

us1234
جمعه 10 مهر 1394, 07:57 صبح
همه اینا درسته ولی تو قرعه کشی وقتی عددی که در میاد اگر به هیچ کاربری تخصیص داده نشده باشه در بدترین حالت سه میلیون و سی صد هزار بار باید قرعه کشی تکرار بشه و این یعنی سه میلیون و سیصد هزار چک کردن دیتابیس!!
و این که preg_match رو هم باهاش این کار رو نمیشد انجام داد (درد سر زیاد داشت) بنابراین کل json ها رو گرفتم و دیکد کردم ازش یک آرایه به دست اومد و توی اون آرایه سمت php با in_array چک میکنم که عددی که درمیاد واسه کاربری ثبت شده یا نه...
به نظر شما حالا کدوم بهتره LIKE یا in_array...


فکر میکنم یا من اشتباه میکنم یا شما :)

ببنید شما یک فیلد به کاربران اضافه کردید که اعداد با فرمت json است . وقتی یک عدد در قرعه کشی خارج شد فقط یک کوئری لازمه تا کل عداد کاربران بررسی شود ! ( بالا گفتم با یک like )

در ثانی اگر در هر قرعه کشی تعداد اعداد خارج شده بیشتر شد باز میتوانید بین like ها OR بذارید ( یعنی برای هر تعداد عدد فقط یک کوئری لازم است که بتوانید کاربران را پیدا کنید )

اگر کوئری زدید و عدد پیدا شده به هیچ کاربری اختصاص نشده بود ، قرعه کشی را تکرار کنید با یک عدد دیگه ( ولی اوصولا نباید این چنین باشد چون قرعه کشی صحیح یعنی جامعه احتمال دقیقا در دسترس باشد و بین آنها یکی انتخاب شود نه که مثلا شما اعداد 1 تا 1 میلیون را بریزید داخل آرایه و از این عداد فقط 500 تا به کاربران اختصاص داده شده باشد )

H:Shojaei
جمعه 10 مهر 1394, 10:29 صبح
نه شما اشتباه میکنید نه من اشتباه میکنم فقط در جریان کامل نحوه عدد دادن به کاربرا نیستید..
ببینید اگر کاربرا ۵ امتیاز داشته باشن باید از فاکتوریل 3 واسشون استفاده کنم یعنی با اعداد ۱ و ۲ و ۳ میشه ۶ عدد ساخت که بدون تکرار باشن حالا اینجا ۵ عددش تخصیص داده میشه به کاربرانی که این ۵ امتیاز رو دارن...
حالا اینجا ۱ عدد میمونه که به هیچکس تخصیص داده نشده اگر قرعه کشی انجام بشه و همین یک عدد در بیاد باید دوباره انجام بشه و همینجا یعنی ۲ کوئری اجرا میشه...
حالا اگر تعداد امتیاز ها ۷۲۱ باشه از فاکتوریل 6 که نمیشه استفاده کرد میشه ۷۲۰ عدد بدون تکرار پس باید از فاکتوریل 7 استفاده کنم که میشه 5040 عدد حالا این تعداد ۷۲۱ عددش به کاربرا تخصیص داده میشه و باقی میمونه...
اگر تو قرعه کشی هر بار عددی انتخاب بشه که تو اون اعدادی که به کاربرها تخصیص داده نشده باشه در بدترین حالت باید 4279 بار باید کوئری لایک گرفته بشه که هیچکدوم واسه کاربرها تخصیص داده نشده...

واسه اینه که میگم این تعداد کوئری گاهی باید انجام بشه...