How can I bundle search terms into more efficient queries? How can I bundle search terms into more efficient queries? php php

How can I bundle search terms into more efficient queries?


I got the following code:

function keyMultiSort(&$array,                      $key,                      $reverse = false,                      $priority_last = false,                      $save_key = true,                      Callable $func = null){    if ($func === null)    {        $func = function ($first, $second) use ($key, $reverse, $priority_last)        {            if (!isset($first[$key]))            {                return ($reverse === false) ? -1 : 1;            }            if (!isset($second[$key]))            {                return ($reverse === false) ? 1 : -1;            }            if ($first[$key] > $second[$key])            {                return ($reverse === false) ? 1 : -1;            }            if ($first[$key] < $second[$key])            {                return ($reverse === false) ? -1 : 1;            }            if ($first[$key] === $second[$key])            {                return ($priority_last === false) ? 1 : -1;            }            return 0;        };    }    if ($save_key)    {        uasort($array, $func);    }    else    {        usort($array, $func);    }}$array = [    ['foo', 'bar'],    ['boo', 'bar'],    ['goo', 'bar'],    ['hoo', 'doo'],    ['foo', 'manchu'],    ['moo', 'bar'],    ['too', 'bar'],    ['foo', 'fighters'],    ['blue kazoo', 'bar'],];$pairs = [];$str = '';foreach($array as $item){    if(!isset($pairs[$item[0]]['count']))    {        $pairs[$item[0]]['count'] = 1;    }    else    {        $pairs[$item[0]]['count']++;    }    $pairs[$item[0]]['elements'][] = $item[1];    if(!isset($pairs[$item[1]]['count']))    {        $pairs[$item[1]]['count'] = 1;    }    else    {        $pairs[$item[1]]['count']++;    }    $pairs[$item[1]]['elements'][] = $item[0];    keyMultiSort($pairs, 'count', true);}$remove = [];foreach($pairs as $elm=>$item){    $remove[] = $elm;    $elements = array_diff($item['elements'], $remove);    if(empty($elements))    {        if (in_array($elm, $remove))        {            continue;        }        $str .= $elm.PHP_EOL;    }    else    {        $str .= $elm.' AND ('.implode(' OR ', $elements).')'.PHP_EOL;    }    $remove = array_merge($remove, $elements);}var_dump($str);

Result:

string(99) "bar AND (foo OR boo OR goo OR moo OR too OR blue kazoo)foo AND (manchu OR fighters)hoo AND (doo)"

It can be optimized, depending on the objectives...


I understand the logic but you really need to make the question clearer.

Anyway, I see this as a graph problem where we want to find the set of nodes that are have highest degree and can span the whole graph.

enter image description here

I believe if you picture it this way, you can use any data structure you like to serve the purpose. You could create an adjacency list and then find nodes with higher degree and then check to see if all elements are covered through those nodes. The matter of adding AND, OR is just simple afterwards.


Code for processing more than 2 values

<?phpfunction keyMultiSort(&$array,                      $key,                      $reverse = false,                      $priority_last = false,                      $save_key = true,                      Callable $func = null){    if ($func === null)    {        $func = function ($first, $second) use ($key, $reverse, $priority_last)        {            if (!isset($first[$key]))            {                return ($reverse === false) ? -1 : 1;            }            if (!isset($second[$key]))            {                return ($reverse === false) ? 1 : -1;            }            if ($first[$key] > $second[$key])            {                return ($reverse === false) ? 1 : -1;            }            if ($first[$key] < $second[$key])            {                return ($reverse === false) ? -1 : 1;            }            if ($first[$key] === $second[$key])            {                return ($priority_last === false) ? 1 : -1;            }            return 0;        };    }    if ($save_key)    {        uasort($array, $func);    }    else    {        usort($array, $func);    }}$array = [    ['foo', 'bar', 'test'],    ['boo', 'bar'],    ['goo', 'bar'],    ['hoo', 'doo', 'test', 'test2'],    ['foo', 'manchu'],    ['moo', 'bar'],    ['too', 'bar'],    ['foo', 'fighters'],    ['blue kazoo', 'bar', 'test'],];$pairs = [];$str = '';foreach($array as $item){    foreach($item as $key=>$elm)    {        foreach($item as $key2=>$elm2)        {            if($key !== $key2)            {                if(!isset($pairs[$elm]['count']))                {                    $pairs[$elm]['count'] = 1;                }                else                {                    $pairs[$elm]['count']++;                }                $pairs[$elm]['elements'][] = $elm2;            }        }    }    keyMultiSort($pairs, 'count', true);}//var_dump($pairs);$remove = [];foreach($pairs as $elm=>$item){    $remove[] = $elm;    $elements = array_diff($item['elements'], $remove);    if(empty($elements))    {        if (in_array($elm, $remove))        {            continue;        }        $str .= $elm.PHP_EOL;    }    else    {        $str .= $elm.' AND ('.implode(' OR ', array_unique($elements)).')'.PHP_EOL;    }}var_dump($str);

Response:

string(184) "bar AND (foo OR test OR boo OR goo OR moo OR too OR blue kazoo)test AND (foo OR hoo OR doo OR test2 OR blue kazoo)foo AND (manchu OR fighters)hoo AND (doo OR test2)doo AND (test2)"

P.S. I hope I have correctly understood the task ...

UPDATE Added code which not ignores "single values". I changed logic:

...

['"yellow balloon"', 'foo', 'bar', 'baz', 'qut'],

...

return:

...

qut AND ("yellow balloon" OR baz)baz AND ("yellow balloon")

...

It seems to me, for this task, that's correct (to conditions to combine more than 2 values).

function keyMultiSort(&$array,                      $key,                      $reverse = false,                      $priority_last = false,                      $save_key = true,                      Callable $func = null){    if ($func === null)    {        $func = function ($first, $second) use ($key, $reverse, $priority_last)        {            if (!isset($first[$key]))            {                return ($reverse === false) ? -1 : 1;            }            if (!isset($second[$key]))            {                return ($reverse === false) ? 1 : -1;            }            if ($first[$key] > $second[$key])            {                return ($reverse === false) ? 1 : -1;            }            if ($first[$key] < $second[$key])            {                return ($reverse === false) ? -1 : 1;            }            if ($first[$key] === $second[$key])            {                return ($priority_last === false) ? 1 : -1;            }            return 0;        };    }    if ($save_key)    {        uasort($array, $func);    }    else    {        usort($array, $func);    }}$array = [    ['foo', 'bar', 'test'],    ['boo', 'bar'],    ['goo', 'bar'],    ['hoo', 'doo', 'test', 'test2'],    ['foo', 'manchu'],    ['moo', 'bar'],    ['too', 'bar'],    ['foo', 'fighters'],    ['"blue kazoo"', 'bar', 'test'],    ['"red panda"', 'bar', 'test'],    ['"yellow balloon"', 'foo', 'bar', 'baz', 'qut'],    ['"red panda"', 'fighters', 'moo'],    ['"foo fighters"'],    ['foo'],    ['bar'],];$pairs = [];$singles = [];$str = '';foreach ($array as $item){    foreach ($item as $key => $elm)    {        if(count($item) === 1)        {            $singles[$elm] = 1;        }        else        {            if (!isset($pairs[$elm]))            {                $pairs[$elm]['count'] = 0;                $pairs[$elm]['elements'] = [];            }            foreach ($item as $key2 => $elm2)            {                if ($key !== $key2)                {                    $pairs[$elm]['count']++;                    $pairs[$elm]['elements'][] = $elm2;                }            }        }    }    keyMultiSort($pairs, 'count', true);}//var_dump($pairs);exit;$remove = [];foreach ($pairs as $elm => $item){    $remove[] = $elm;    $elements = array_diff($item['elements'], $remove);    $elements = array_unique($elements);    if (!empty($elements)){        $str .= $elm.' AND ('.implode(' OR ', $elements).')'.PHP_EOL;    }}foreach ($singles as $elm => $item){    $str .= $elm.PHP_EOL;}var_dump($str);

Response:

string(421) "bar AND (foo OR test OR boo OR goo OR moo OR too OR "blue kazoo" OR "red panda" OR "yellow balloon" OR baz OR qut)test AND (foo OR hoo OR doo OR test2 OR "blue kazoo" OR "red panda")foo AND (manchu OR fighters OR "yellow balloon" OR baz OR qut)"red panda" AND (fighters OR moo)qut AND ("yellow balloon" OR baz)baz AND ("yellow balloon")test2 AND (hoo OR doo)fighters AND (moo)doo AND (hoo)"foo fighters"foobar"

P.S. In my opinion, this problem does not apply to reality