0

I have database with list of similar words. I need to get similar words and I am trying this approach to get every similar word:

  1. I am using LIKE on mysql query to get similar words.
  2. It's not enough to use LIKE, so I make every possible string with % to get more similar results. I don't know and I can't find if there is any LIKE alternative to find much more relevant queries.

So for example to find similar words like "EL", I am using this query:

SELECT * FROM `words` WHERE word LIKE 'el' OR word LIKE '%el' OR word LIKE '%el%' OR word LIKE '%e%l%'

And it returns only one result, which is not what I want to. However if I would use multi_query and multiple queries like:

SELECT * FROM `words` WHERE word LIKE 'el';
SELECT * FROM `words` WHERE word LIKE '%el';
SELECT * FROM `words` WHERE word LIKE '%el%';
SELECT * FROM `words` WHERE word LIKE '%e%l%';

To fetch these I use:

if ($con->multi_query($query)) {
do {
    /* almacenar primer juego de resultados */
    if ($result = $con->store_result()) {
        while ($row = $result->fetch_row()) {
            printf("%s\n", $row[0]);
        }
        $result->free();
    }
    /* mostrar divisor */
    if ($con->more_results()) {
        printf("-----------------\n");
    }
    } while ($con->next_result());
}

/* cerrar conexión */
$con->close();

These are (example/similar) results I get with it:

el,espinel,el,wheels,espinel,wheels

It would get all the possible results. Of course I would need to filter the duplicates, but I would get them all.

For single query I use:

$result = $con->query($query);
$row = mysqli_fetch_row($result);

However I think multiple queries and filtering would take more time then single query, so I am looking for a way to get all the results on single query or even better without creating all possible variations of string.

Eray Balkanli
  • 7,752
  • 11
  • 48
  • 82
Simon
  • 1,314
  • 4
  • 14
  • 26
  • 3
    `'%el%' ` matches the previous queries' results, you don't need to do all of them. – aynber Oct 19 '17 at 12:28
  • 1
    If the first query only returns one result I would guess there is only one row matching your query. Can you show some sample data, your current output and your expected output? – waka Oct 19 '17 at 12:29
  • The 3 query's return more because it contains double results. – Mark Baijens Oct 19 '17 at 12:30
  • 1
    `%e%l%` will match all results that contain an `e` and an `l` as long as they are in that order. So the only one you actually need is the last one, the others are redundant. – GrumpyCrouton Oct 19 '17 at 12:32
  • If you are looking for a way to paramaterize this, might I suggest: `$term = "%".implode(str_split("STRING"),'%')."%";` - this will insert a wildcard character between each letter and the beginning and end of the string. – GrumpyCrouton Oct 19 '17 at 12:38
  • Thanks for your comments. I made changes on the my question answering your questions. I've added the codes I use to fetch results and what I get from it. – Simon Oct 19 '17 at 12:45
  • @GrumpyCrouton I've wrote a code in php which adds % after each letter, after 2nd letter, after 3d letter and so on, so it makes a ton of variations out of a single word. – Simon Oct 19 '17 at 12:46
  • @Simon Yes, mine works for _any_ word, just replace "STRING" with the word. As I said, you only need the 1 search term, the one with the % between each letter. All of the other search terms are irrelevant afterward, they are redundant. – GrumpyCrouton Oct 19 '17 at 12:47

1 Answers1

0

As mentioned already, you only need to run the last query. In order to get the desired order of the results (relevance), you'd need to implement that logic via php.

$keyword = 'Your search term';

function getRelevance($value,$keyword){
    $value = strtolower($value);
    $keyword = strtolower($keyword);

    $index = strpos($value, $keyword);
    $word_index = strpos($value, ' '.$keyword);

    if($index==0) // first word starts with keyword
        return 3;
    else if($word_index!==false) // any word starts with keyword
        return 2;
    else if($index!==false) // keyword matches anywhere
        return 1;
    else
        return 0;
}

$keyword = mysqli_real_escape_string($con, $keyword); // prevent SQL injection
$res = $con->query("SELECT * FROM words WHERE `word` LIKE '%$keyword%'");

$words = array();
while($line = $res->fetch_assoc()){
    $line['relevance'] = getRelevance($line['word'],$keyword); // assign relevance value based on the "el" query and the elements word
    $words[] = $line;
}

function compareRelevance($a,$b){
    return $b['relevance'] - $a['relevance'];
}
usort($words,'compareRelevance');

This will fetch all matching entries from the 'words' table and sort them based on the search term.

Manuel Otto
  • 6,410
  • 1
  • 18
  • 25
  • Where does `$el` come from? – GrumpyCrouton Oct 19 '17 at 12:42
  • @GrumpyCrouton check OP's post, he referred to the search term as `el`... – Manuel Otto Oct 19 '17 at 12:43
  • Yes, but not as a variable, and it's not declared in your code so it will throw errors. Not to mention, that's just an example of the search data, I don't think you would name the variable that. – GrumpyCrouton Oct 19 '17 at 12:43
  • Sorry, I'm kind of annoying ^.^ - [Little Bobby](http://bobby-tables.com/) says the code in your answer **[may be at risk for SQL Injection Attacks](https://stackoverflow.com/q/60174/)**. **Please** _add a warning about this_, and you should include information on [Prepared Statements](https://en.wikipedia.org/wiki/Prepared_statement) for [MySQLi](http://php.net/manual/en/mysqli.quickstart.prepared-statements.php) or [PDO](http://php.net/manual/en/pdo.prepared-statements.php). – GrumpyCrouton Oct 19 '17 at 12:48
  • ohhhh right. well catched. I copied that from one of my snippets where I did the escaping before. thx – Manuel Otto Oct 19 '17 at 12:52
  • [Even _escaping parameters_ is NOT safe!](https://stackoverflow.com/questions/5741187/sql-injection-that-gets-around-mysql-real-escape-string/12118602#12118602) – GrumpyCrouton Oct 19 '17 at 13:02
  • Awesome man, thank you for your answer and the code, it helped me a lot! @ManuelOtto – Simon Oct 19 '17 at 13:06