Статьи

Матчи — это новая жара

                          

Как вы помогаете человеку без работы найти его в Интернете? Экран поиска. Как вы помогаете человеку найти любовь в Интернете? Экран поиска. Как вы находите, какую камеру купить онлайн? Экран поиска. Как вы помогаете больному самодиагностировать в Интернете? Понятия не имею, я иду к врачу. Неважно, что я хочу сказать вам, что есть другой способ.

                                                      

Теперь поиск отличный. Обычно это помогает людям найти то, что они ищут … но иногда им приходится копаться в тоннах вещей, которые им не нужны. Зачем? Потому что люди обычно могут думать о том, что они хотят, но не о том, что они не хотят возвращаться. Таким образом, вы получите массу результатов, которые не очень важны для вашего пользователя … и если вы не являетесь одним из основных поисковых систем, ваш поиск не очень умный.

Ваш поиск знает о вашем пользователе? Знает ли он, что у вашего пользователя есть права на просмотр?
Как это связано с персональными рекомендациями? Использует ли он то, что мы уже знаем о пользователе? Этот последний вопрос является наиболее важным, и я хочу показать вам, как вы можете использовать графическую базу данных, такую ​​как Neo4j, чтобы помочь вашим пользователям по-разному находить то, что они хотят.

Представьте, что вы ищете работу. Подумайте о том, что вы положили в свое резюме. Ваше местоположение, ваше образование, история вашей работы, ваши навыки, ваши рекомендации и т. Д. Теперь представьте, что вы работаете. Да, я знаю, я прошу вас быть неодушевленным объектом. Просто дай ему шанс. Что вы хотите в кандидате? Кто-то рядом с вашим местоположением, с определенным уровнем образования и набором навыков, предпочтительно проверенный кем-то, кого вы уважаете, и т. Д.

И кандидат на работу, и кандидатура на работу думают об одних и тех же вещах, но если вы посмотрите на резюме и описание работы, вы поймете, что они не говорят на одном языке. Почему бы и нет? Это так очевидно, что это сводило меня с ума в течение многих лет и было одной из причин, по которой я создал Vouched и попал в эту базу данных Graph Database. Итак, давайте решим эту проблему с помощью графика.

Я собираюсь сделать так, чтобы кандидаты и рабочие должности говорили на одном языке, соединяя их с узлами местоположения и навыков. Я держу вещи простыми, все, что имеет отношение как к людям, так и к работе, может быть использовано.

Мэри живет в Калифорнии, знает C # и знает PostgreSQL. Существует вакансия, которая требует, чтобы кандидат был в Калифорнии, знал C # и знал PostgreSQL. Мы соединяем эти два вместе в нашем графике так:

Теперь мы можем использовать наш график, чтобы перейти от Марии к этой работе или любой другой работе, где она будет отличным кандидатом с помощью следующего запроса Cypher .

START me=node:users_index(name={user})
MATCH skills<-[:has]-me-[:lives_in]->city<-[:in_location]-job-[:requires]->requirements
WHERE me-[:has]->()<-[:requires]-job
WITH DISTINCT city.name AS city_name, job.name AS job_name,
LENGTH(me-[:has]->()<-[:requires]-job) AS matching_skills,
LENGTH(job-[:requires]->()) AS job_requires,
COLLECT(DISTINCT requirements.name) AS req_names, COLLECT(DISTINCT skills.name) AS skill_names
RETURN city_name, job_name, FILTER(name IN req_names WHERE NOT name IN skill_names) AS missing
ORDER BY matching_skills / job_requires DESC, job_requires
LIMIT 10

That looks a little complicated, let’s break it down piece by piece.

START me=node:users_index(name={user})

We start with the things we know, and right now all we know is we have a user named Mary that we can look up in our users_index and use as our starting point in the traversal. This query will be used by other users, so we parametrize it with {user}.

MATCH skills<-[:has]-me-[:lives_in]->city<-[:in_location]-job-[:requires]->requirements

Then we look for patterns in the graph that look like this MATCH segment above. Cypher knows “me”, it doesn’t know anything else, but as it traverses relationships from “me” it assigns nodes and relationships along the way as we name them. This is a little different if you are used to SQL where all your tables already have a name. Here I am naming all nodes that have an outgoing relationship of type “has” from “me” as skills. Because that is what they are in my mind, I could have called those nodes anything else, it doesn’t matter to Neo4j. I do the same for other nodes along the pattern.

WHERE me-[:has]->()<-[:requires]-job

I only want to match jobs WHERE I share at least one skill that it requires. Notice we are using a pattern as our where clause. We don’t name the nodes in between because at this point we only care that one exists.

WITH DISTINCT city.name AS city_name, job.name AS job_name,

We can chain queries together using the WITH clause which pipes the results from one query to the next. The DISTINCT clause returns only the unique records found. Here we start by passing the name property of both city and job.

LENGTH(me-[:has]->()<-[:requires]-job) AS matching_skills,

We continue to capture results that we want to pass to the next query. Here we are using the LENGTH clause not to find the length of the path between a user and jobs since we know that’s just 2 hops away, but instead using it to find the number of paths that exist between them.

LENGTH(job-[:requires]->()) AS job_requires,

We use the same trick again to get the number of skills required by each job.

COLLECT(DISTINCT requirements.name) AS req_names, COLLECT(DISTINCT skills.name) AS skill_names

Then we COLLECT the names of the requirements and skills into two arrays.

RETURN city_name, job_name, FILTER(name IN req_names WHERE NOT name IN skill_names) AS missing

We then RETURN the values we are interested in, and use the FILTER clause to return only the names of the skills of a job we do not know.

ORDER BY matching_skills / job_requires DESC, job_requires

We then ORDER BY the percentage of skills the user matches for the job in DESCending order, and use the number of required skills of the job as a tie breaker.

LIMIT 10

Lastly we LIMIT the number of results to the top 10.

We now have data we can display to a user.

A user would then be able to see what jobs they qualify for and what jobs they almost qualify for. Maybe they do know those skills and just forgot to mention it in their profile, or maybe it’s something they can learn quickly… or they can lie.

If you implement this in such a way that you get the user’s skills and location up front, you don’t even need to provide a search screen, and instead go right into results.

You can see it running live on Heroku and as always, the code is available on Github.

If you think you might have a use for this solution don’t hesitate to get in touch and I’ll be happy help.