سؤال

ونسخة مختصرة:

ولدي الإعداد مماثلة لستاكوفيرفلوو. للمستخدمين الحصول على الانجازات. لدي العديد من المزيد من الإنجازات من SO، دعونا نقول بناء على أمر من 10K، ولكل مستخدم في 100s من الإنجازات. والآن، كيف تنصحين (التوصية) تحقيق المقبل لمستخدم في محاولة ل؟

ونسخة طويل:

وعلى غرار الكائنات مثل هذا في جانغو (يظهر فقط أجزاء هامة):

class User(models.Model):
    alias = models.ForeignKey(Alias)

class Alias(models.Model):
    achievements = models.ManyToManyField('Achievement', through='Achiever')

class Achievement(models.Model):
    points = models.IntegerField()

class Achiever(models.Model):
    achievement = models.ForeignKey(Achievement)
    alias = models.ForeignKey(Alias)
    count = models.IntegerField(default=1)

ووبلدي الخوارزمية هو فقط لتجد كل مستخدم آخر له تحقيق مشترك مع قاموا بتسجيل الدخول، ثم تذهب من خلال جميع إنجازاتهم والترتيب حسب عدد التكرارات:

def recommended(request) :
    user = request.user.get_profile()

    // The final response
    r = {}

    // Get all the achievements the user's aliases have received 
    // in a set so they aren't double counted
    achievements = set()
    for alias in user.alias_set.select_related('achievements').all() :
        achievements.update(alias.achievements.all())

    // Find all other aliases that have gotten at least one of the same
    // same achievements as the user
    otherAliases = set()
    for ach in achievements :
        otherAliases.update(ach.alias_set.all())

    // Find other achievements the other users have gotten in addition to
    // the shared ones.
    // And count the number of times each achievement appears
    for otherAlias in otherAliases :
        for otherAch in otherAlias.achievements.all() :
            r[otherAch] = r.get(otherAch, 0) + 1

    // Remove all the achievements that the user has already gotten
    for ach in achievements :
        r.pop(ach)

    // Sort by number of times the achievements have been received
    r = sorted(r.items(), lambda x, y: cmp(x[1], y[1]), reverse=True)

    // Put in the template for showing on the screen
    template_values = {}
    template_values['achievements'] = r

ولكن الأمر يحتاج إلى الأبد لتشغيل، ويعود دائما اللائحة بأكملها، وهو لزوم لها. ومن شأن يحتاج المستخدم فقط أعلى الإنجازات القليلة للذهاب بعد.

وهكذا، وأنا نرحب بالتوصيات على خوارزميات أخرى و / أو تحسينات التعليمات البرمجية. سأعطيك إنجازا في نظام بلدي لطرح خوارزمية توصية:)

هل كانت مفيدة؟

المحلول

وأسلوب واحد يمكنك نوصي التي انجازات للذهاب لهو أن نرى كيف العديد من المستخدمين لديها بالفعل تلك الإنجازات ويوصي أولئك الشعبية. عندما حققت تلك التي ذهبت إلى أسفل القائمة والتوصية منها قليلا أقل شعبية. ومع ذلك، وهذا له افتراض السذاجة أن الجميع يريد أن يذهب للإنجازات الشعبية. قد يسبب انجازات شعبية لتكون أكثر منها شعبية وأقل شعبية، وأيضا ... والعزاء هو أن هذا لا يستغرق الكثير من الموارد، ومن المرجح أن تشغيل سريع جدا. (فقط الحفاظ على قائمة الإنجازات + عدد المرات هو تحقيقه)

وهناك طريقة أخرى (والذي يحاول تخمين أي إنجازات غير المرجح أن تذهب بعد على أساس الإنجازات ما كان بالفعل المستخدم) هو استخدام بعض خوارزميات تعلم الآلة. أعتقد أن ك أقرب الجيران خوارزمية سوف تؤدي بشكل جيد هنا. تحديد عتبة وفقط كل شيء الانتاج الذي هو فوق هذه العتبة. الآن، أنا لا أعرف إذا كان هذا سوف تعمل بشكل أسرع مما كان لديك بالفعل، ولكن يجب فقط تشغيل المحرك توصية مرة واحدة في كل مرة قام بها المستخدم إنجازا جديدا، تخزين أعلى (دعنا نقول) خمسة، وإخراج عادل ذلك إلى المستخدم كلما كانت هناك حاجة توصية.

وآمل أن يساعد هذا. =)

نصائح أخرى

وأود أن أقترح عليك أن تفعل الخطوات الثلاث الأولى (الإنجازات، otherAliases، العد)، وبيان واحد SQL واحد. كما هو عليه الآن، وأنت إصدار الكثير من الاستفسارات ويلخص الآلاف من الصفوف في بيثون وهي مهمة يجب أن تفوض DB. على سبيل المثال رمز

for otherAlias in otherAliases : #For every single other user
    for otherAch in otherAlias.achievements.all() : #execute a query
        r[otherAch] = r.get(otherAch, 0) + 1

هل الآلاف من الاستفسارات ضخمة.

وبدلا من ذلك، يمكنك استخدام SQL للقيام بذلك من خلال الانضمام الناجح على نفسها على أساس الاسم المستعار معرف كونها مختلفة وتحقيق الهوية هي نفسها. يمكنك ثم المجموعة من قبل معرف الإنجاز وتشغيل العد.

في الاستعلام أدناه، على الطاولة "B" هو الإنجازات المستخدم الآخر و "الناجح" هو إنجازاتنا. إذا كان أي مستخدم آخر يشارك إنجازا، فإنها تظهر مرة واحدة في "B" لكل الإنجاز إلا أنهما يشتركان. نحن بعد ذلك مجموعة تلك التي alias_id وحساب عدد المرات التي ظهرت حتى تحصل على معرف لطيفة، عد الجدول بها.

وكود جدا صعبة للغاية (لا SQL المتوفرة هنا)

SELECT B.Alias_id, COUNT(B.achievement_id) 
  FROM Achiever, Achiever as B 
  WHERE Achiever.achievement_id == B.achievement_id 
     AND Achiever.Alias_id == <insert current user alias here>;
  GROUP BY B.Alias_id

وإذا كان هذا يعمل بالطريقة اعتقد انه سيكون، سوف تحصل على جدول الأسماء المستعارة المستخدم أخرى، جنبا إلى جنب مع عدد من الإنجازات التي مشاركتها مع المستخدم الحالي.

ووالشيء التالي الذي فعله هو عبارة SQL التي يستخدم واحد أعلاه ك "الداخلية اختر" - الذي يطلق عليه المستخدمين. يمكنك الانضمام أنه مع الجدول إنجازاتك والجدول الناجح الخاص للمستخدم الحالي. قد ترغب في تجاهل جميع ولكن أكبر 10 المستخدمين الذين تشبه المستخدم الحالي.

وليس لدي الوقت لكتابة استعلام جيدة الآن، ولكن ننظر إلى الانضمام لبيان DB الخاص الذي ينضم على achievement_id بين المرشحين 10 المستخدمين والمستخدم الحالي - وضع هذا id لNULL إذا كانت لا توجد الآن ' ر الوجود. مرشح فقط لالصفوف حيث ظهر NULL (إنجازات الغير منجز).

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top