Add similarity score for users (#942)

This commit is contained in:
Ben Halpern 2018-10-17 11:53:28 -04:00 committed by GitHub
parent 7d783c2b9f
commit 305492c2c8
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 132 additions and 39 deletions

View file

@ -33,11 +33,7 @@ class Internal::UsersController < Internal::ApplicationController
handle_mentorship
add_note
@user.update!(user_params)
if params[:quick_match]
redirect_to "/internal/users/unmatched_mentee"
else
redirect_to "/internal/users/#{@user.id}"
end
redirect_to "/internal/users/unmatched_mentee"
end
def handle_mentorship

View file

@ -0,0 +1,63 @@
class UserSimilarity
STOP_WORDS = %w(
a cannot into our thus about co is ours to above
could it ourselves together across down its out too
after during itself over toward afterwards each last own
towards again eg latter per under against either latterly
perhaps until all else least rather up almost elsewhere
less same upon alone enough ltd seem us along etc
many seemed very already even may seeming via also ever
me seems was although every meanwhile several we always
everyone might she well among everything more should were
amongst everywhere moreover since what an except most so
whatever and few mostly some when another first much
somehow whence any for must someone whenever anyhow
former my something where anyone formerly myself sometime
whereafter anything from namely sometimes whereas anywhere
further neither somewhere whereby are had never still
wherein around has nevertheless such whereupon as have
next than wherever at he no that whether be hence
nobody the whither became her none their which because
here noone them while become hereafter nor themselves who
becomes hereby not then whoever becoming herein nothing
thence whole been hereupon now there whom before hers
nowhere thereafter whose beforehand herself of thereby why
behind him off therefore will being himself often therein
with below his on thereupon within beside how once
these without besides however one they would between i
only this yet beyond ie onto those you both if or
though your but in other through yours by inc others
throughout yourself can indeed otherwise thru yourselves'
).freeze
attr_accessor :first_user, :second_user
def initialize(first_user, second_user)
@first_user = first_user
@second_user = second_user
end
def score
mentorship_score + profile_score + tag_score
end
def mentorship_score
(first_user.mentee_description.to_s.tr("0-9", "").split(" ") & second_user.mentor_description.to_s.tr("0-9", "").split(" ") - STOP_WORDS).size +
(first_user.mentor_description.to_s.tr("0-9", "").split(" ") & second_user.mentee_description.to_s.tr("0-9", "").split(" ") - STOP_WORDS).size
end
def profile_score
summary_score = (first_user.summary.to_s.split(" ") & second_user.summary.to_s.split(" ") - STOP_WORDS).size
mostly_work_with_score = (first_user.mostly_work_with.to_s.split(" ") & second_user.mostly_work_with.to_s.split(" ") - STOP_WORDS).size
summary_score + mostly_work_with_score
end
def tag_score
tag_intersection.delete("discuss")
tag_intersection.delete("hiring")
tag_intersection.size * 2
end
def tag_intersection
first_user.cached_followed_tag_names & second_user.cached_followed_tag_names
end
end

View file

@ -108,41 +108,38 @@
<% count = 0 %>
<% MentorRelationship.
unmatched_mentors.where.not(mentor_form_updated_at: nil, id: @user.id).
order("mentor_form_updated_at DESC").each do |possible_mentor| %>
<% break if count > 20 %>
<% tag_intersection = ( @user.cached_followed_tag_names & possible_mentor.cached_followed_tag_names ) %>
<% if tag_intersection.any? %>
<% count = count + 1 %>
<div class="row" style="font-size:0.9em">
<div class="col-md-2">
<img src="<%= possible_mentor.profile_image_90 %>" style="border-radius:100px;width:50px;height:50px;" />
<br/>
<a href="/<%= possible_mentor.username %>" target="_blank">@<%= possible_mentor.username %></a>
<br/>
<a href="/intertnal/users/<%= possible_mentor.id %>" target="_blank">Internal(<%= possible_mentor.id %>)</a>
</div>
<div class="col-md-3" style="border-left:1px solid black">
<h4>Tag Intersection</h4>
<%= tag_intersection.join(", ") %>
</div>
<div class="col-md-3">
<h4>Mentor description</h4>
<%= possible_mentor.mentor_description %>
</div>
<div class="col-md-3">
<h4>Skills/Languages</h4>
<%= possible_mentor.mostly_work_with %>
</div>
<div class="col-md-1">
<h4>Action</h4>
<%= form_for ([:internal, @user]) do |f| %>
<%= f.hidden_field :quick_match, value: true %>
<%= f.hidden_field :add_mentor, value: possible_mentor.id %>
<%= f.submit "Match!" %>
<% end %>
</div>
order("mentor_form_updated_at DESC").limit(175).
sort_by { |possible_mentor| UserSimilarity.new(@user, possible_mentor).score }.reverse.
first(20).each do |possible_mentor| %>
<div class="row" style="font-size:0.9em">
<div class="col-md-2">
<img src="<%= possible_mentor.profile_image_90 %>" style="border-radius:100px;width:50px;height:50px;" />
<br/>
<a href="/<%= possible_mentor.username %>" target="_blank">@<%= possible_mentor.username %></a>
<br/>
<a href="/intertnal/users/<%= possible_mentor.id %>" target="_blank">Internal(<%= possible_mentor.id %>)</a>
</div>
<% end %>
<div class="col-md-3" style="border-left:1px solid black">
<h4>Tag Intersection</h4>
<%= UserSimilarity.new(@user, possible_mentor).tag_intersection.join(", ") %>
</div>
<div class="col-md-3">
<h4>Mentor description</h4>
<%= possible_mentor.mentor_description %>
</div>
<div class="col-md-3">
<h4>Skills/Languages</h4>
<%= possible_mentor.mostly_work_with %>
</div>
<div class="col-md-1">
<h4>Action</h4>
<%= form_for ([:internal, @user]) do |f| %>
<%= f.hidden_field :quick_match, value: true %>
<%= f.hidden_field :add_mentor, value: possible_mentor.id %>
<%= f.submit "Match!" %>
<% end %>
</div>
</div>
<% end %>
<% end %>

View file

@ -0,0 +1,29 @@
require "rails_helper"
RSpec.describe UserSimilarity, vcr: {} do
let(:user) { create(:user, summary: "I like ruby and JavaScript and Go") }
let(:similar_user) { create(:user, summary: "I like JavaScript and Go") }
let(:dissimilar_user) { create(:user, summary: "I like Haskell and functional programming") }
it "It returns similar user" do
simialar_score = UserSimilarity.new(user, similar_user).score
dissimialar_score = UserSimilarity.new(user, dissimilar_user).score
expect(simialar_score).to be > dissimialar_score
end
it "Is not affected by stop words" do
user.summary = user.summary + " throughout yourself can indeed otherwise thru yourselves through yours by inc others"
dissimilar_user.summary = dissimilar_user.summary + " throughout yourself can indeed otherwise thru yourselves through yours by inc others"
simialar_score = UserSimilarity.new(user, similar_user).score
dissimialar_score = UserSimilarity.new(user, dissimilar_user).score
expect(simialar_score).to be > dissimialar_score
end
it "Is affected by non-stop words" do
user.mentee_description = "Hot dogs languages punk rock hello"
dissimilar_user.mentor_description = "Hot dogs languages punk rock hello "
simialar_score = UserSimilarity.new(user, similar_user).score
dissimialar_score = UserSimilarity.new(user, dissimilar_user).score
expect(simialar_score).to be < dissimialar_score
end
end

View file

@ -119,6 +119,10 @@ RSpec.describe NotifyMailer, type: :mailer do
mentee_email = described_class.mentee_email(mentee, mentor)
expect(mentee_email.subject).to eq "You have been matched with a DEV mentor!"
end
it "renders proper from" do
mentee_email = described_class.mentee_email(mentee, mentor)
expect(mentee_email.from).to include "liana@dev.to"
end
end
describe "#mentor_email" do
@ -128,6 +132,10 @@ RSpec.describe NotifyMailer, type: :mailer do
mentor_email = described_class.mentor_email(mentor, mentee)
expect(mentor_email.subject).to eq "You have been matched with a new DEV mentee!"
end
it "renders proper subject" do
mentor_email = described_class.mentor_email(mentor, mentee)
expect(mentor_email.from).to include "liana@dev.to"
end
end
end
end