-
Notifications
You must be signed in to change notification settings - Fork 86
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
UserTaskMatcher gets tasks with most overlapping skills fixes #736 #752
base: develop
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
defmodule CodeCorps.UserTaskMatcher do | ||
@moduledoc """ | ||
Find the top tasks most matching a User's skills | ||
""" | ||
|
||
alias CodeCorps.{Repo, Task, User, TaskSkill} | ||
import Ecto.Query | ||
|
||
@spec match_user(User.t, number) :: [Task.t] | ||
def match_user(%CodeCorps.User{} = user, tasks_count) do | ||
query = from t in TaskSkill, | ||
join: skill in assoc(t, :skill), | ||
join: user_skill in assoc(skill, :user_skills), | ||
join: user in assoc(user_skill, :user), | ||
where: user.id == ^user.id, | ||
group_by: t.task_id, | ||
order_by: count(t.task_id), | ||
limit: ^tasks_count, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I actually kind of wonder if we shouldn't do the |
||
select: t.task_id | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Have you been able to run an EXPLAIN on this query by chance to see how well it performs? |
||
|
||
matches = query |> Repo.all | ||
|
||
Task |> where([t], t.id in ^matches) |> Repo.all | ||
end | ||
end |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
defmodule CodeCorps.UserTaskMatcherTest do | ||
use CodeCorps.ModelCase | ||
|
||
import CodeCorps.UserTaskMatcher | ||
|
||
test "can find top x tasks for a user's skill" do | ||
coding = insert(:skill, title: "coding") | ||
design = insert(:skill, title: "design") | ||
|
||
account_page = insert(:task) | ||
settings_page = insert(:task) | ||
photoshop = insert(:task) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. These could maybe be rethought a little to tell a clearer story. Like one could be There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This comment probably conflicts slightly with the suggestion to chain, but with the right ordering could be resolvable. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That's what i was going for with skills that were implementing an entire page (thus needing I did start to wonder sometimes about using just the most overlapping tasks as the sort priority. I could see someone like me selecting 'design' as a tag (even though that's a stretch). Then I'd get a list of results back that were design heavy, even though I'd be better suited for a task that simply overlaps my strongest skill, (Seems like this would be more clear when we saw real data instead of speculating what the data would be.) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah I think this is simply the most naive approach right now. I'd prefer some sort of recommender system generally but we're a ways off from that. |
||
|
||
insert(:task) | ||
|
||
insert(:task_skill, task: account_page, skill: design) | ||
insert(:task_skill, task: account_page, skill: coding) | ||
insert(:task_skill, task: settings_page, skill: design) | ||
insert(:task_skill, task: settings_page, skill: coding) | ||
insert(:task_skill, task: photoshop, skill: coding) | ||
|
||
user = insert(:user) | ||
|
||
insert(:user_skill, user: user, skill: design) | ||
insert(:user_skill, user: user, skill: coding) | ||
|
||
tasks = match_user(user, 2) | ||
|
||
assert(length(tasks) == 2) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You might be able to write this as |
||
assert(length(match_user(user, 3)) == 3) | ||
end | ||
end |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -12,6 +12,7 @@ defmodule CodeCorps.Skill do | |
has_many :roles, through: [:role_skills, :role] | ||
|
||
has_many :project_skills, CodeCorps.ProjectSkill | ||
has_many :user_skills, CodeCorps.UserSkill | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can this go last to keep alpha order? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. should There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes! |
||
has_many :projects, through: [:project_skills, :project] | ||
|
||
timestamps() | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would write some inline documentation here and rename to
tasks_limit
or something more intention revealing.