Разбиение логической строки поиска на составные части / подсчет причин совпадений SQL SELECT - PullRequest
0 голосов
/ 09 апреля 2019

Согласно моему предыдущему вопросу , программный рекрутер может ввести булеву текстовую строку , например C++ AND ((UML OR Python) OR (not Perl)), которую я переведу на SELECT * FROM candidates WHERE skill=C++ AND ((skill=UML OR skill=Python) OR (not skill=Perl)).

[Обновить] Я выделил , например , потому что некоторые ответы, кажется, думают, что меня интересует только этот запрос. Это только пример. Я ищу универсальное решение, написанное на PHP. Может быть, регулярное выражение? Просто некоторый код, который находит все подслови запроса, так что я могу запрашивать подтермы индивидуально. [/ Update]

Я мог бы COUNT(*) указать количество совпадений, но мне также было бы очень интересно узнать, насколько каждый "подпункт" (если это правильный термин) запроса вносит свой вклад в результат.

например. могло быть 200 кандидатов с C ++, но 50 не подходили, потому что у них нет ни опыта UML, ни языка Python.

Итак, используя PHP (и rexex?) Или MySql, как я могу разбить это, чтобы увидеть, какие части поискового запроса способствуют получению результата?

То есть, разбить skill=C++ AND ((skill=UML OR skill=Python) OR (not skill=Perl)) на COUNT(*) WHERE skill=C++ и `COUNT (*) WHERE (навык = UML ИЛИ навык = Python) и т. Д.

Я не знаю, есть ли у MySql какой-то EXPLAIN для этого, но не подозреваю, что мне придется выделять SELECT, как описано, и COUNT каждый подпункт отдельно.

Я надеюсь, что я объяснил это ясно; если нет, пожалуйста, попросите разъяснений. Я просто не знаю с чего начать

Ответы [ 6 ]

1 голос
/ 24 апреля 2019

Хотя это не самое элегантное решение, функция WITH ROLLUP Mysql может быть полезной.См. https://dev.mysql.com/doc/refman/8.0/en/group-by-modifiers.html

. В простейшем методе вы можете написать этот запрос, чтобы получить уникальные умения:

SELECT skill, COUNT(skill) AS mycount
FROM cands
GROUP BY skill WITH ROLLUP

. Это вернет общее количество всех умений со строкой NULL.внизу с итогом, как это:

|skill   |mycount  |
|--------|---------|
|C++     |  2      |
|Java    |  3      |
|Python  |  4      |
|<i>NULL</i>    |  9      |

Добавив логические операции, вы можете получить более сложный результат:

SELECT skill, COUNT(skill) AS mycount, SUM(IF(skill='C++' || skill='Python', 1, 0)) AS CorPython
FROM cands
GROUP BY skill WITH ROLLUP

С этим вторым параметром, CorPythonСтолбец будет суммировать - в последней строке NULL - общее количество людей с "C или Python".Вы можете сделать это логическое сечение настолько сложным, насколько это необходимо.

|skill   |mycount  |CorPython  |
|--------|---------|-----------|
|C++     |  2      |  2        |
|Java    |  3      |  0        |
|Python  |  4      |  4        |
|<i>NULL</i>    |  9      |  6        |   <-- This is the value you want (6)
1 голос
/ 19 апреля 2019

Нам нужен метод для разделения условий.Однако мы не можем разделить AND и OR как равные, потому что AND имеют более высокий приоритет по сравнению с OR .

Так в примере, подобном этому:

Cond1 AND Cond2 OR Cond3

Мы не можем разделить на AND|OR потому что мы пропустили бы Cond1 AND Cond2 в целом.

Поэтому первое, что нужно сделать, это добавить дополнительные скобки (с регулярными выражениями), где это необходимо, чтобы следующий алгоритм правильно разделил условия.В предыдущем примере это было бы (Cond1 AND Cond2) OR Cond3.

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

Каждое условие сохраняется в массиве и затем отправляется для обработки (рекурсивно).Это связано с тем, что некоторые условия могут быть сложными и иметь вложенные условия.

Все эти условия и подусловия хранятся в массиве.

Как только вы выполнили все условия (и подусловия)) у вас есть две альтернативы для монтирования SQL.

Первым вариантом будет один запрос без предложения WHERE и одна SUM для каждого условия.Это, вероятно, лучше всего, если в таблице не так много строк

Второй вариант - запуск нескольких запросов SELECT count(*) со всеми условиями.

Я оставляю здесь код php.Я также добавил опцию для настройки максимального количества уровней гнезда при разделении условий.

У вас есть демо на Ideone , здесь .

<?php

$conditions = 'C++ AND ((UML OR Python) OR (not Perl))';

// Other tests...
//$conditions = "C++ AND Python OR Perl";
//$conditions = "C++ AND Python OR Perl OR (Perl AND (Ruby AND Docker AND (Lisp OR (C++ AND Ada) AND Java)))";

///////// CONFIGURATION /////////
$maxNest = 0; // Set to 0 for unlimited nest levels
/////////////////////////////////

print "Original Input:\n";
print $conditions . "\n\n";

// Add implicit parenthesis...
// For example: `A AND B OR C` should be: `(A AND B) OR C`
$addParenthesis = '/(?|(((?:\bNOT\b\s*+)?+[^)(\s]++|(?:\bNOT\b\s*+)?+[(](?:\s*+(?2)\s*+)*+[)])(?:\s*+\bAND\b\s*+((?2)))++)(?=\s*+\bOR\b\s*+)|\s*+\bOR\b\s*+\K((?1)))/im';
while (preg_match($addParenthesis, $conditions)) {
  $conditions = preg_replace($addParenthesis, '(\1)', $conditions);
}

print "Input after adding implicit parenthesis (if needed):\n";
print $conditions . "\n\n";

// Optional cleanup: Remove useless NOT () parenthesis
$conditions = preg_replace('/[(]\s*((?:NOT\s*)?+(\S+))\s*[)]/i', '\1', $conditions);

// Optional cleanup: Remove useless NOT NOT...
$conditions = preg_replace('/\bNOT\s+NOT\b/i', '', $conditions);

$list_conditions = [$conditions];

function split_conditions($input, $level = 0) {
  global $list_conditions, $maxNest;

  if ($maxNest > 0 && $level >= $maxNest) { return; }

  // If it is a logic operator, skip
  if ( preg_match('/^\s*(?:AND|OR)\s*$/i', $input) ) {
    return;
  }

  // Add condition to the list:
  array_push($list_conditions, $input);

  // Don't go on if this is a single filter
  if ( preg_match('/^\s*(?:NOT\s+)?+[^)(\s]+\s*$/i', $input) ) {
    return;
  }

  // Remove parenthesis (if exists) before evaluating sub expressions
  // Do this only for level > 0. Level 0 is not guaranteed to have
  // sorrounding parenthesis, so It may remove wanted parenthesis 
  // such in this expression: `(Cond1 AND Cond2) OR (Cond3 AND Cond4)`
  if ($level > 0) {
    $input = preg_replace('/^\s*(?:NOT\b\s*)?+[(](.*)[)]\s*$/i', '\1', $input);
  }

  // Fetch all sub-conditions at current level:
  $next_conds = '/((?:\bNOT\b\s*+)?+[^)(\s]++|(?:\bNOT\b\s*+)?+[(](?:\s*+(?1)\s*+)*+[)])/i';
  preg_match_all($next_conds, $input, $matches);

  // Evaluate subexpressions
  foreach ($matches[0] as $match) {
    split_conditions($match, $level + 1);
  }
}

split_conditions($conditions);

// Trim and remove duplicates
$list_conditions = array_unique(array_map(function($x){
  return preg_replace('/^\s*|\s*$/', '', $x);
}, $list_conditions));

// Add columns
$list_conditions = array_map(function($x){
  return preg_replace('/([^\s()]++)(?<!\bAND\b)(?<!\bOR\b)(?<!\bNOT\b)/i', "skill='$1'", $x);
}, $list_conditions);

print "Just the conditions...\n\n";
print_r($list_conditions);
print "\n\n";

print "Method 1) Single query with multiple SUM\n\n";
$sum_conditions = implode(",\n", array_map(function($x){
  return "    SUM( $x )";
}, $list_conditions));
$sumSQL = "SELECT\n$sum_conditions\nFROM candidates;";
print $sumSQL . "\n\n";

print "Method 2) Multiple queries\n\n";
$queries = implode("\n", array_map(function($x){
  return "SELECT count(*) from candidates WHERE $x;";
}, $list_conditions));
print $queries . "\n\n";
0 голосов
/ 20 апреля 2019

Привет, это не абигатная сделка, остерегайтесь

$sqlresult =array ('php, html, php, c++, perl');
//that is array result from MySQL and now we need to count every term alone only in php

//now I create this 
function getcount ($word, $paragraphp){
if (preg_match("/$word/i", $paragraph))
    $count = 1;
else
    $count = 0;

return $count;
}

foreach ( $sqlresult as $key ) {
$finalresult = array ();
$finalresult['$key'] += getcount($key, $key);
}

//now retrieve results as following 

$php = " results for php word is $finalresult[php]";
$perl = "results for perl word is $finalresult[perl]";
echo $php;
echo $perl;

Если у вас есть параграф с большим количеством слов, вы должны сначала преобразовать его в массив с функцией разнесения php и запустить шаги, как указано выше

Inбольшой проект, который не подходит, вам нужна хорошая замена MySQL. В этом случае я предлагаю поиск по SPHINX. После того, как вы запустите запрос в SPHINX, выполните этот запрос

SHOW META;

. Это даст каждое слово в вашем поиске с количеством посещений дляподробности проверьте это http://sphinxsearch.com/docs/current/sphinxql-show-meta.html

0 голосов
/ 19 апреля 2019
  1. Пересчитать таблицу из SELECT skill, COUNT(*) FROM tbl и дополнений.
  2. Предоставьте полную таблицу из шага 1; пусть вербовщик посмотрит в список.

Чтобы стать более любопытным, просто уберите из текстовой строки парен, ИЛИ И И, чтобы получить различные упомянутые навыки. Затем отобразите только те.

Но ни один из них не обрабатывает (UML OR Python) или несмежные вещи, такие как (C++ and not Perl). В любом случае, сколько вы ожидаете от своего примера? Существует также (UML OR Python) AND C++ и еще несколько.

Даже не думайте о разборе через SQL; использовать некоторый клиентский язык. Или задайте вопрос кандидатам.

Подсказки по коду

В Perl можно сделать следующее:

$str =~ s{[()]|AND|OR|NOT}{ }ig;
$str =~ s{ +}{ }g;
@skills = split('  ', $str);

PHP-код будет использовать preg_replace и explode, но в остальном будет похожим. В вашем примере C++ AND ((UML OR Python) OR (not Perl)) станет массивом ['C ++', 'UML', 'Python', 'Perl']

0 голосов
/ 18 апреля 2019
SELECT
 count(*),
 sum(skill=C++),
 sum(skill=UML),
 sum(skill=Python),
 sum(not skill=Perl)
FROM candidates WHERE TRUE
AND skill=C++
AND (FALSE
  OR (FALSE
       OR skill=UML
       OR skill=Python)
  OR (not skill=Perl)
)

0 голосов
/ 18 апреля 2019

Как насчет использования встроенных возможностей полнотекстового поиска MySQL ?Возвращение автоматически ранжируется с лучшими совпадениями в верхней части.

Вы можете создать новый столбец, который содержит все навыки кандидата.Тогда поиск по этому полю даст вам ранжированные результаты.

Функции полнотекстового поиска

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...