Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

method to get a dictionary of {user_pair:previous meeting count} #98

Merged
merged 1 commit into from
Jul 28, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 45 additions & 5 deletions tests/match_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,10 @@

from yelp_beans.logic.subscription import get_specs_from_subscription
from yelp_beans.logic.subscription import store_specs_from_subscription
from yelp_beans.matching.group_match import get_previous_meetings_counts
from yelp_beans.matching.match import generate_meetings
from yelp_beans.matching.pair_match import get_previous_pair_meetings
from yelp_beans.matching.match_utils import get_counts_for_pairs
from yelp_beans.matching.match_utils import get_previous_meetings
from yelp_beans.matching.pair_match import save_pair_meetings
from yelp_beans.models import Meeting
from yelp_beans.models import MeetingParticipant
Expand Down Expand Up @@ -98,7 +100,7 @@ def test_get_previous_meetings(minimal_database):
MeetingParticipant(meeting=meeting, user=user2).put()
MeetingParticipant(meeting=meeting, user=user1).put()

assert get_previous_pair_meetings(subscription) == set([(user1.id(), user2.id())])
assert get_previous_meetings(subscription) == set([(user1.id(), user2.id())])


def test_get_previous_meetings_multi_subscription(minimal_database):
Expand All @@ -114,8 +116,25 @@ def test_get_previous_meetings_multi_subscription(minimal_database):
MeetingParticipant(meeting=meeting, user=user2).put()
MeetingParticipant(meeting=meeting, user=user1).put()

assert get_previous_pair_meetings(subscription1) == set([(user1.id(), user2.id())])
assert get_previous_pair_meetings(subscription2) == set([])
assert get_previous_meetings(subscription1) == set([(user1.id(), user2.id())])
assert get_previous_meetings(subscription2) == set([])


def test_get_previous_multi_meetings(minimal_database):
pref_1 = SubscriptionDateTime(datetime=datetime.now() - timedelta(weeks=MEETING_COOLDOWN_WEEKS - 1)).put()
subscription = MeetingSubscription(title='all engineering weekly', datetime=[pref_1]).put()
user_pref = UserSubscriptionPreferences(preference=pref_1, subscription=subscription).put()
user1 = User(email='a@yelp.com', metadata={'department': 'dept'}, subscription_preferences=[user_pref]).put()
user2 = User(email='a@yelp.com', metadata={'department': 'dept2'}, subscription_preferences=[user_pref]).put()
meeting_spec = MeetingSpec(meeting_subscription=subscription, datetime=pref_1.get().datetime).put()
meeting1 = Meeting(meeting_spec=meeting_spec, cancelled=False).put()
meeting2 = Meeting(meeting_spec=meeting_spec, cancelled=False).put()
MeetingParticipant(meeting=meeting1, user=user2).put()
MeetingParticipant(meeting=meeting1, user=user1).put()
MeetingParticipant(meeting=meeting2, user=user2).put()
MeetingParticipant(meeting=meeting2, user=user1).put()

assert get_previous_meetings(subscription) == set([(user1.id(), user2.id()), (user1.id(), user2.id())])


def test_get_previous_meetings_no_specs(database_no_specs):
Expand All @@ -129,7 +148,7 @@ def test_get_previous_meetings_no_specs(database_no_specs):
MeetingParticipant(meeting=meeting, user=user2).put()
MeetingParticipant(meeting=meeting, user=user1).put()

assert get_previous_pair_meetings(subscription) == set([])
assert get_previous_meetings(subscription) == set([])


def test_generate_save_meetings(minimal_database, subscription):
Expand Down Expand Up @@ -177,3 +196,24 @@ def test_no_re_matches(minimal_database):
matches, unmatched = generate_meetings(users, meeting_spec, previous_meetings)
assert len(unmatched) == num_users - 2
assert [(match[0].key.id(), match[1].key.id()) for match in matches] == [(users[0].key.id(), users[1].key.id())]


def test_pair_to_counts():
pairs = [('user1', 'user2'), ('user1', 'user2'), ('user2', 'user3')]
counts = get_counts_for_pairs(pairs)
assert (counts[('user2', 'user3')] == 1)
assert(counts[('user1', 'user2')] == 2)


def test_get_previous_meetings_counts():
pref_1 = SubscriptionDateTime(datetime=datetime.now() - timedelta(weeks=MEETING_COOLDOWN_WEEKS - 1)).put()
subscription = MeetingSubscription(title='all engineering weekly', datetime=[pref_1]).put()
user_pref = UserSubscriptionPreferences(preference=pref_1, subscription=subscription).put()
user1 = User(email='a@yelp.com', metadata={'department': 'dept'}, subscription_preferences=[user_pref]).put()
user2 = User(email='b@yelp.com', metadata={'department': 'dept2'}, subscription_preferences=[user_pref]).put()
meeting_spec = MeetingSpec(meeting_subscription=subscription, datetime=pref_1.get().datetime).put()
meeting = Meeting(meeting_spec=meeting_spec, cancelled=False).put()
MeetingParticipant(meeting=meeting, user=user2).put()
MeetingParticipant(meeting=meeting, user=user1).put()

assert(get_previous_meetings_counts([user1.get(), user2.get()], subscription) == {(user1.id(), user2.id()): 1})
19 changes: 19 additions & 0 deletions yelp_beans/matching/group_match.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# -*- coding: utf-8 -*-
from __future__ import absolute_import
from __future__ import print_function
from __future__ import unicode_literals

import itertools

from yelp_beans.matching.match_utils import get_counts_for_pairs
from yelp_beans.matching.match_utils import get_previous_meetings


def get_previous_meetings_counts(users, subscription):
previous_meetings = get_previous_meetings(subscription)
counts_for_pairs = get_counts_for_pairs(previous_meetings)
userids = sorted([user.key.id() for user in users])
all_pairs_counts = {pair: 0 for pair in itertools.combinations(userids, 2)}
for pair in counts_for_pairs:
all_pairs_counts[pair] = counts_for_pairs[pair]
return all_pairs_counts
79 changes: 79 additions & 0 deletions yelp_beans/matching/match_utils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
# -*- coding: utf-8 -*-
from __future__ import absolute_import
from __future__ import print_function
from __future__ import unicode_literals

import logging
from collections import defaultdict
from datetime import datetime
from datetime import timedelta

from google.appengine.ext import ndb

from yelp_beans.logic.config import get_config
from yelp_beans.models import Meeting
from yelp_beans.models import MeetingParticipant
from yelp_beans.models import MeetingSpec


def get_counts_for_pairs(pairs):
counts = {}
for pair in pairs:
if pair in counts:
counts[pair] += 1
else:
counts[pair] = 1
return counts


def get_previous_meetings(subscription, cooldown=None):

if cooldown is None:
cooldown = get_config()['meeting_cooldown_weeks']

meetings = defaultdict(list)

# get all meeting specs from x weeks ago til now
time_threshold_for_meetings = datetime.now() - timedelta(weeks=cooldown)

meeting_spec_keys = [
spec.key for spec in MeetingSpec.query(
ndb.AND(MeetingSpec.datetime > time_threshold_for_meetings,
MeetingSpec.meeting_subscription == subscription)
).fetch()
]

logging.info('Previous Meeting History: ')
logging.info([meeting.get().datetime.strftime("%Y-%m-%d %H:%M") for meeting in meeting_spec_keys])

if meeting_spec_keys == []:
return set([])

# get all meetings from meeting specs
meeting_keys = [meeting.key for meeting in Meeting.query().filter(
Meeting.meeting_spec.IN(meeting_spec_keys)).fetch()]

if meeting_keys == []:
return set([])

# get all participants from meetings
participants = MeetingParticipant.query().filter(
MeetingParticipant.meeting.IN(meeting_keys)
).fetch()

if participants == []:
return set([])

# group by meeting Id
for participant in participants:
meetings[participant.meeting.id()].append(participant.user)

# ids are sorted, all matches should be in increasing order by id for the matching algorithm to work
disallowed_meetings = set([tuple(sorted(meeting, key=lambda Key: Key.id())) for meeting in meetings.values()])

logging.info('Past Meetings')
logging.info([tuple([meeting.get().get_username() for meeting in meeting]) for meeting in disallowed_meetings])

disallowed_meetings = {tuple([meeting.id() for meeting in meeting]) for meeting in disallowed_meetings}

return disallowed_meetings
62 changes: 2 additions & 60 deletions yelp_beans/matching/pair_match.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,13 @@

import itertools
import logging
from collections import defaultdict
from datetime import datetime
from datetime import timedelta

import networkx as nx
from google.appengine.ext import ndb

from yelp_beans.logic.config import get_config
from yelp_beans.logic.user import user_preference
from yelp_beans.matching.match_utils import get_previous_meetings
from yelp_beans.models import Meeting
from yelp_beans.models import MeetingParticipant
from yelp_beans.models import MeetingSpec


def get_disallowed_meetings(users, prev_meeting_tuples, spec):
Expand Down Expand Up @@ -53,59 +48,6 @@ def save_pair_meetings(matches, spec):
))


def get_previous_pair_meetings(subscription, cooldown=None):

if cooldown is None:
cooldown = get_config()['meeting_cooldown_weeks']

meetings = defaultdict(list)

# get all meeting specs from x weeks ago til now
time_threshold_for_meetings = datetime.now() - timedelta(weeks=cooldown)

meeting_spec_keys = [
spec.key for spec in MeetingSpec.query(
ndb.AND(MeetingSpec.datetime > time_threshold_for_meetings,
MeetingSpec.meeting_subscription == subscription)
).fetch()
]

logging.info('Previous Meeting History: ')
logging.info([meeting.get().datetime.strftime("%Y-%m-%d %H:%M") for meeting in meeting_spec_keys])

if meeting_spec_keys == []:
return set([])

# get all meetings from meeting specs
meeting_keys = [meeting.key for meeting in Meeting.query().filter(
Meeting.meeting_spec.IN(meeting_spec_keys)).fetch()]

if meeting_keys == []:
return set([])

# get all participants from meetings
participants = MeetingParticipant.query().filter(
MeetingParticipant.meeting.IN(meeting_keys)
).fetch()

if participants == []:
return set([])

# group by meeting Id
for participant in participants:
meetings[participant.meeting.id()].append(participant.user)

# ids are sorted, all matches should be in increasing order by id for the matching algorithm to work
disallowed_meetings = set([tuple(sorted(meeting, key=lambda Key: Key.id())) for meeting in meetings.values()])

logging.info('Past Meetings')
logging.info([tuple([meeting.get().get_username() for meeting in meeting]) for meeting in disallowed_meetings])

disallowed_meetings = {tuple([meeting.id() for meeting in meeting]) for meeting in disallowed_meetings}

return disallowed_meetings


def generate_pair_meetings(users, spec, prev_meeting_tuples=None):
"""
Returns 2 tuples:
Expand All @@ -114,7 +56,7 @@ def generate_pair_meetings(users, spec, prev_meeting_tuples=None):
- unmatched_user_ids: users with no matches.
"""
if prev_meeting_tuples is None:
prev_meeting_tuples = get_previous_pair_meetings(spec.meeting_subscription)
prev_meeting_tuples = get_previous_meetings(spec.meeting_subscription)

uid_to_users = {user.key.id(): user for user in users}
user_ids = sorted(uid_to_users.keys())
Expand Down