- Вспоминая каменный век рекрутинга, до появления искусственного интеллекта
- Построение данных о кандидатах
- Начало работы с Algolia
- Изучение некоторых интересных опций, которые мы получаем с Algolia
- Прототип мини-поиска кандидатов
- Добавление элементов пользовательского интерфейса Algolia
- Бонус: добавление информации о событиях!
- В заключение
Вспоминая каменный век рекрутинга, до появления искусственного интеллекта
Возможно, вы все знаете или не знаете обо мне то, что я нашел свой путь в технологию через очень нетрадиционный путь: рекрутинг! Нет, я не был рекрутером, я был рекрутером.
В те времена моей славой было то, что я был сертифицирован по логическому булеву поиску. Это пригодилось мне, когда я работал на государственных подрядах. Для многих наших сотрудников требовались очень специфические и редкие сочетания допуска к работе с одним или несколькими сертификатами. Когда я впервые услышал об инструментах Algolia для поиска, ранжирования и рекомендаций на основе искусственного интеллекта, я вспомнил те дни, которые я провел в напряженном поиске кандидатов. Естественно, мне было интересно узнать, что может быть возможно теперь, когда искусственный интеллект способен выполнять задачи, которые раньше были долгими и утомительными.
Исходя из этого, присоединяйтесь ко мне, пока я изучаю некоторые возможности Algolia! Я выбрал для этого VueJS, но это было почти наугад, учитывая огромное количество доступных языковых SDK, с которыми вы можете ознакомиться здесь.
Небольшое замечание перед началом: команда Algolia платит мне за изучение инструмента и запись моего непредвзятого опыта, поэтому все мнения ниже являются моими собственными.
Построение данных о кандидатах
Прежде чем рассмотреть, как инструменты Algolia могут облегчить поиск кандидатов, я хотел приблизительно представить данные о кандидатах. Я придумал некоторую логику, которая представляла бы сочетание навыков и ключевых слов, которые кто-то может искать. (Я начал эту работу с этого проекта Vue, если вы хотите проследить за ним). Я почти ожидал, что уже есть что-то вроде tech-ipsum или professional-ipsum, на которые я мог бы опереться для этой задачи, но, к сожалению, я ничего не нашел!
Итак, для начала в корне моего проекта Vue я создал небольшой файл seed.js
со следующей логикой, чтобы сгенерировать для нас несколько «кандидатов».
// seed.js
const fs = require("fs");
const seedData = {
weights: [2, 3, 5, 8],
roles: ["backend", "frontend", "fullstack"],
termMap: {
backend: ["back-end", "python", "pytest", "django", "sql", "nosql", "redis", "AWS", "api", "ci/cd"],
fullstack: ["full-stack", "python", "javascript", "css", "sql", "api", "ui", "html","databases", "typescript", "react"],
frontend: ["front-end", "ui", "ux", "design", "accessibility", "css", "tailwind", "javascript", "react", "typescript" ]
},
titles: [
"software engineer",
"senior software engineer",
"software developer",
"programmer",
"software development engineer"
],
randomAchievements: [
"Led adoption of ",
"Increased throughput of systems using ",
"Introduced quality standards for ",
"Enhanced testing of ",
"Coached more junior employees in ",
"Recognized subject matter expert for ",
"Led research effort on improvements to our ",
"Decreased bugs by 50 percent related to ",
"Created platform with ",
"Spearheaded workshops to train colleagues in "
],
candidateList: []
}
function getRandomArrayItems(items, quantity) {
let randomItems = []
for(let i=0; i < quantity; i++) {
randomItems.push(items[Math.floor(Math.random() * items.length)]);
}
return randomItems;
}
function generateCandidateData() {
// Silly little function to generate some candidate profiles
let candidates = [];
for(let i=0; i <= 10; i++) {
const weight = getRandomArrayItems(seedData.weights, 1)[0];
seedData.roles.forEach(role => {
const achievementList = getRandomArrayItems(seedData.randomAchievements, weight);
let profile = {
title: `${role} ${getRandomArrayItems(seedData.titles, 1)[0]}`
}
let achievementsWithTechKeywords = []
achievementList.map(achievement => {
achievementsWithTechKeywords.push(
`${achievement} ${getRandomArrayItems(seedData.termMap[role], weight).join(", ")}`
);
})
profile["resume"] = `${achievementsWithTechKeywords.join(". ")}.`;
candidates.push(profile);
})
}
seedData.candidateList = candidates;
};
function writeCandidateData() {
fs.writeFile("./candidates.json", JSON.stringify(seedData.candidateList), err => {
if(err) console.error(err);
})
};
generateCandidateData();
writeCandidateData();
Перейдя в терминал, я собираюсь быстро запустить эту логику, чтобы сгенерировать файл JSON, который мы затем сможем использовать в Algolia, запустив node seed.js
.
Посмотрев в редактор кода, я получил файл candidates.json
, полный немного бессмысленных, но смутно напоминающих техническое резюме данных, с небольшим примером, показанным ниже.
Это не обязательно те, кого я собираюсь нанять в свою команду завтра, но для начала достаточно приблизительный пример. Переходим к звезде нашего шоу, Algolia!
Начало работы с Algolia
Если вы следите за нами, создайте бесплатный аккаунт в Algolia, чтобы узнать, что будет дальше. Мы пройдем через их простой мастер «начала работы» и сначала создадим индекс под названием candidates
.
Я собираюсь подключить JSON-файл, который мы создали ранее, хотя Algolia также предлагает API-клиент, который сделает эту задачу очень простой и программно.
После отправки мы перенаправляемся на приборную панель, где теперь можем увидеть список наших данных.
Изучение некоторых интересных опций, которые мы получаем с Algolia
Когда вы дойдете до этой точки, некоторые подсказки в накладке для начала работы быстро предложат вам изучить некоторые из более интересных опций, которые предлагает этот инструмент, включая опции настройки. Для начала мы можем выбрать игнорирование или включение атрибутов. Для начала я включаю и resume
, и title
.
Почему эта опция классная? Ну, мне бы точно пригодилась возможность игнорировать title
при поиске кандидатов. На моей первой работе по подбору персонала мы работали с ужасным клиентом, у которого все должности ИТ-поддержки были названы очень банально: Support Services Technician
или что-то столь же непроизносимое. Мне не потребовалось много времени, чтобы понять, что ключевые слова в резюме будут гораздо лучше определять соответствие требованиям, чем что-либо связанное с названиями. Такой уровень контроля помог бы мне в этом. Вы также можете настроить этот тип поиска как часть системы отслеживания кандидатов (ATS), чтобы помочь анонимизировать части профилей кандидатов, чтобы уменьшить любой элемент предвзятости. Например, если наши данные структурированы таким образом, что включают поля «Образование» и «Год окончания», вы можете игнорировать год окончания, чтобы уменьшить вероятность эйджизма. Algolia объясняет больше о преимуществах настраиваемых атрибутов здесь, если вам интересно!
У нас также есть возможность настроить поля, наиболее важные для ранжирования
. Поскольку я здесь экспериментирую, я собираюсь настроить ранжирование исключительно на поле резюме. Мой гипотетический сценарий заключается в том, что я буду больше заинтересован в совпадении по навыкам Python, чем в том, чтобы зацикливаться на том, является ли кто-то разработчиком программного обеспечения или инженером-программистом. Это позволяет обойти поле title
, которое мы создали для наших данных.
Последний вариант, за который я был бы убит, когда набирал сотрудников, лучше всего понять через небольшую предысторию.
Когда я занимался подбором персонала для государственных учреждений, очень часто люди имели «синонимичные» дипломы, сертификаты или показатели статуса, которые имели огромное значение для их привлекательности, но не всегда были четко выражены. Одним из примеров является сертификат CompTIA Security +, которому многие люди, работающие в сфере государственных контрактов, обучаются и получают сертификаты без отрыва от работы в соответствии с директивой Министерства обороны (8750, в частности). Некоторые из этих людей настолько погружены в свой мир, что не оптимизируют свое резюме для поиска, поэтому вы можете найти их только в списке директив, требующих их сертификации. В Algolia есть возможность создать список ключевых слов-синонимов, которые могли бы избавить меня от долгих напряженных поисков типа security AND (engineer OR specialist OR analyst) and (8750 or "Security +" or "Security+)
and so on and so forth. Опция синонимов очень проста в использовании, как показано ниже:
Прототип мини-поиска кандидатов
Чтобы применить некоторые из этих классных опций, я создал простую аппроксимацию страницы поиска кандидатов на основе того редкого скелета приложения Vue, на который я ссылался ранее. Не стесняйтесь пропустить это, но я собрал небольшое количество CSS, чтобы это выглядело разумно, в тегах <style></style>
нашего файла App.vue
:
// App.vue
<style>
button.ais-SearchBox-submit,
button.ais-SearchBox-reset {
display:none;
}
input {
margin:2em;
}
html {
background-color:#edeff5;
margin:4em;
}
h3 {
color: #3c4fe0;
letter-spacing:.04ch;
}
h5 {
font-family: Arial, Helvetica, sans-serif;
letter-spacing:.03ch;
color:#5a5e9a;
line-height: 0.4rem;
margin:2.5rem;
}
span#header {
display:flex;
justify-content:space-between;
}
span#header img {
height:25px;
width:25px;
}
div.searchResults {
background-color:white;
padding:3rem;
margin:2rem;
}
.ais-SearchBox-input {
/* background-color: white; */
height:45px;
width:100%;
margin:0px;
}
.ais-InstantSearch {
width:50%;
margin:auto;
}
.ais-Hits {
margin-top:1rem;
}
.ais-Hits-item p{
font-size: 1.5rem;
margin:0rem 2.5rem 1rem 2.5rem;
line-height: 2.25rem;
}
.ais-SearchBox-form {
background-color: inherit;
margin-bottom:2rem;
height:8rem;
}
</style>
А в разделе <head></head>
нашего public/index.html
, связанного с этим минимальным CSS фреймворком, который мне нравится, Wing:
<link rel="stylesheet" href="https://unpkg.com/wingcss"/>
Добавление элементов пользовательского интерфейса Algolia
Мне бы хотелось, чтобы мои усилия в этой части звучали более интересно, но действительно, имеющиеся здесь возможности позволили подключить этот минимальный пользовательский интерфейс к Algolia относительно легко. Для поиска Algolia предлагает ряд библиотек пользовательского интерфейса, включая библиотеку для Vue. Вы можете ознакомиться с некоторыми из них здесь.
🛑 ✋ Небольшое замечание: мы собираемся поместить наш ключ API Algolia в файл
.env
. Это совершенно нормально, если вы уверены, что не дали этому конкретному API-ключу никаких опасных разрешений. Это хорошая вещь, чтобы проверить перед началом работы, если вы этого еще не сделали.
С учетом сказанного, чтобы получить эти значения, перейдите на вкладку главного меню приборной панели API Keys
. Здесь мы хотим получить ID нашего приложения и API-ключ только для поиска.
Вернувшись к терминалу, выполним следующие команды для установки необходимых пакетов Algolia.
npm install algoliasearch vue-instantsearch --save
Затем мы привяжем его к нашему экземпляру Vue в main.js
.
// main.js
import Vue from 'vue'
import App from './App.vue'
import './registerServiceWorker'
import InstantSearch from 'vue-instantsearch'; // new import
Vue.use(InstantSearch); // now bound to Vue
new Vue({
render: function (h) { return h(App) }
}).$mount('#app')
Теперь давайте внесем некоторые изменения в App.vue
, чтобы выполнить несколько задач:
- Мы собираемся использовать раздел markdown, чтобы использовать готовые виджеты поиска, доступные через эту библиотеку, которые очень удобны.
- Мы собираемся использовать логику JavaScript для подключения к нашим ранее загруженным данным и предоставления наших записей
Во-первых, давайте обновим раздел <template></template>
в App.vue
, чтобы теперь включить виджет поиска и отображения, который Algolia имеет удобный для Vue.
// App.vue
<template>
<div>
<center><h3>Turbocharged searches with Algolia</h3></center>
<ais-instant-search :search-client="searchClient" index-name="candidates">
<ais-search-box id="searchInput"/>
<ais-hits>
<template v-slot="{ items }">
<div
:id="item.objectID"
class="searchResults"
v-for="item in items"
:key="item.objectID"
>
<span id="header">
<h5>{{ item.title }}</h5>
</span>
<br/>
<p>{{ item.resume }}</p>
</div>
</template>
</ais-hits>
</ais-instant-search>
</div>
</template>
Далее, в разделе <script></script>
добавим соединение с нашим индексом Algolia.
<script>
import algoliasearch from 'algoliasearch/lite';
export default {
data() {
return {
searchClient: algoliasearch(
process.env.VUE_APP_ALGOLIA_APPLICATION_ID,
process.env.VUE_APP_ALGOLIA_SEARCH_API_KEY
),
};
},
};
</script>
И наконец, вернувшись в терминал, если вы запустите npm run serve
и перейдете в браузер, вы должны получить простой пользовательский интерфейс поиска, как показано ниже, связывающий все эти части вместе:
Мы можем убедиться, что возможности поиска и фильтрации работают, введя некоторые критерии, вы можете видеть, как изменились мои критерии, когда я ввел «frontend».
Вот и все! Действительно, с помощью нескольких простых шагов и, возможно, менее двадцати минут работы, мы создали прототип, который — как бы просто он ни выглядел — использует параметры конфигурации поиска, выбранные нами ранее, и базовый искусственный интеллект, встроенный в поисковый продукт Algolia.
Бонус: добавление информации о событиях!
Если я представлю себя использующим этот инструмент в этих целях, я пойму, что также может существовать научный способ анализа использования моей вымышленной системы поиска кандидатов. Для того чтобы это сработало, нам, возможно, понадобится отслеживание того, на каких кандидатов рекрутер останавливается для дальнейшего рассмотрения, или же многие приложения для поиска кандидатов позволяют вам также сделать их «любимыми».
Чтобы приблизиться к такому поведению, я решил также заставить мой поиск работать с Algolia event insights. Эта область функциональности позволяет отслеживать многочисленные события, будь то клики или избранное, которые могут еще больше повысить релевантность результатов поиска, показываемых пользователям. Более подробную информацию о том, как начать работу с событиями и Algolia, вы можете найти здесь.
Для начала мы сделаем несколько обновлений в App.vue
, которые выполнят несколько действий:
- импортируем библиотеку event/insight из Algolia
- подключает клиент API к нашим учетным данным API, так что события будут отправляться обратно в правильное хранилище данных — хранилище записей наших кандидатов
- подключает клиент Insight к нашему виджету поиска из предыдущего шага
- создает простую логику для отображения иконок, где щелчок по иконке «выбирает» кандидата и запускает отправку события.
Измененные разделы App.vue
показаны ниже:
// App.vue
<template>
<div>
<center><h3>Turbocharged searches with Algolia</h3></center>
<!-- new :middlewares argument connects the insight client to our search widget -->
<ais-instant-search :search-client="searchClient" index-name="candidates" :middlewares="middlewares">
<ais-search-box id="searchInput"/>
<ais-hits>
<template v-slot="{ items, sendEvent }">
<div
:id="item.objectID"
class="searchResults"
v-for="item in items"
:key="item.objectID"
@click="sendEvent('click', item, 'Item Starred')"
>
<span id="header">
<h5>{{ item.title }}</h5>
<img
:id="`img-${item.objectID}`"
src="https://i.imgur.com/5Je2dmA.png"
@click="favorite(`img-${item.objectID}`)"
alt="thumbs up"
/>
</span>
<br/>
<p>{{ item.resume }}</p>
</div>
</template>
</ais-hits>
</ais-instant-search>
</div>
</template>
<script>
import algoliasearch from 'algoliasearch/lite';
// new imports contain what we need to support sending events
import { createInsightsMiddleware } from 'instantsearch.js/es/middlewares';
import aa from 'search-insights';
// reconnecting to the API, so our events/insights go to the right place
aa('init', {
appId: process.env.VUE_APP_ALGOLIA_APPLICATION_ID,
apiKey: process.env.VUE_APP_ALGOLIA_SEARCH_API_KEY
});
// fictitious user token lets our "favorites" be tracked to me
aa('setUserToken', '32f32sfds94s032dfjskal')
const insightsMiddleware = createInsightsMiddleware({
insightsClient: aa,
});
export default {
data() {
return {
searchClient: algoliasearch(
process.env.VUE_APP_ALGOLIA_APPLICATION_ID,
process.env.VUE_APP_ALGOLIA_SEARCH_API_KEY
),
middlewares: [insightsMiddleware]
};
},
methods: {
favorite(id) {
// simple logic flips the icon, for a visual indicator of "favorited" candidates
const icon = document.getElementById(id);
icon.src = "https://i.imgur.com/j635pgy.png";
}
}
};
</script>
Если мы вернемся в наш браузер, то увидим следующее:
Если бы мы имитировали реальный поиск и «отдали предпочтение» некоторым результатам, мы бы увидели сердечки на выбранных кандидатах (вместо иконки с большим пальцем вверх).
А если мы вернемся к нашей приборной панели Algolia (URL: https://www.algolia.com/apps/<id вашего приложения>/events/debugger
), то теперь мы можем видеть, что события отправляются обратно!
В заключение
Честно говоря, между изучением использования веб-скрейперов и знанием того, как легко настроить надежный, настраиваемый пользовательский интерфейс поиска с помощью Algolia, возможно, какая-то параллельная версия меня все еще работает в рекрутинге и специализируется на создании внутренних инструментов поиска кандидатов. Но правда в том, что даже вне крошечной ниши рекрутинга я могу придумать безграничное количество применений для таких удобных инструментов поиска, которые по умолчанию оснащены искусственным интеллектом. Спасибо, что дочитали до этого места, и я буду рад услышать ваши идеи по применению Algolia в комментариях! 🤓