How to sort the results of this code? - php

im creating a search feature that will allow a user to type in a question, my code will then match as many words as possible with the questions already in my MySQL database and display the top 5 results depending on the amount of words that are matched in the question.
I use a count() function which counts the number of matching words, however at the moment the results shown are displayed as the first 5 results in the database that have a 50% word match or more. I want the results to be shown as the highest match first and work its way down for every result in the database but only show the top 5.
Here is the code I have
<?php
include("config.php");
$search_term = filter_var($_GET["s"], FILTER_SANITIZE_STRING); //User enetered data
$search_term = str_replace ("?", "", $search_term); //remove any question marks from string
$search_count = str_word_count($search_term); //count words of string entered by user
$array = explode(" ", $search_term); //Seperate user enterd data
foreach ($array as $key=>$word) {
$array[$key] = " title LIKE '%".$word."%' "; //creates condition for MySQL query
}
$q = "SELECT * FROM posts WHERE " . implode(' OR ', $array); //Query to select data with word matches
$r = mysql_query($q);
$count = 0; //counter to limit results shown
while($row = mysql_fetch_assoc($r)){
$thetitle = $row['title']; //result from query
$thetitle = str_replace ("?", "", $thetitle); //remove any question marks from string
$title_array[] = $thetitle; //creating array for query results
$newarray = explode(" ", $search_term); //Seperate user enterd data again
foreach($title_array as $key => $value) {
$thenewarray = explode(" ", $value); //Seperate each result from query
$wordmatch = array_diff_key($thenewarray, array_flip($newarray));
$result = array_intersect($newarray, $wordmatch);
$matchingwords = count($result); //Count the number of matching words from
//user entered data and the database query
}
if(mysql_num_rows($r)==0)//no result found
{
echo "<div id='search-status'>No result found!</div>";
}
else //result found
{
echo "<ul>";
$title = $row['title'];
$percentage = '.5'; //percentage to take of search word count
$percent = $search_count - ($search_count * $percentage); //take percentage off word count
if ($matchingwords >= $percent){
?>
<li><a href='<?php echo $row['url']; ?>'><?php echo $title ?><i> No. matching words: <?php echo $matchingwords; ?></i></a></li>
<?php
$count++;
if ($count == 5) {break;
}
}else{
}
}
echo "</ul>";
}
?>
The image below shows the what happens when I search "How to make my own website" in the search bar. I already have several questions in the database for testing which are all similar questions and one the last entry is an exact match to the question I asked, but as its currently showing them as the first 5 mathing results, it ignores the full match.
Here is the results from that search.
I have added a bit of code which shows how many word matches there are in each question just so you can see it working a bit better. Also its a coincidence that its in ascending order, it is showing the first 5 matching results in the database.
What code do I need to add to this to arrange it so that it shows the closest match from the entire database first then the second best match, third etc...?

Either you use a nested SQL query where you can order by count or load the values to array php array first and then sort the array. Using SQL is very efficient && faster.
Multi Dimension Array Sorting
select column1, column2,..., LENGTH(titlecolumn) - LENGTH(REPLACE(titlecolumn, '$search term', '')) AS nummatchwords from posts where " . implode(' OR ', $array) order by nummatchwords;

Related

How to order this array to High to Low? [duplicate]

This question already has an answer here:
Closed 10 years ago.
Possible Duplicate:
How to sort the results of this code?
I have made this code which allows a user to type in a search bar a question. This code then takes that question and looks for watching words with questions in my database. It then counts the number of matching words for each question. Once done it then displays the top 4 best matched questions depending on how many words match.
However at the moment it displays these matches from lowest word match to highest word match (low-to-high) and I was it the other way around so that it displays the best match first (high-to-low). How do I do this in this code?
<?php
include("config.php");
$search_term = filter_var($_GET["s"], FILTER_SANITIZE_STRING); //User enetered data
$search_term = str_replace ("?", "", $search_term); //remove any question marks from string
$array = explode(" ", $search_term); //Seperate user enterd data
foreach ($array as $key=>$word) {
$array[$key] = " title LIKE '%".$word."%' "; //creates condition for MySQL query
}
$q = "SELECT * FROM posts WHERE " . implode(' OR ', $array); //Query to select data with word matches
$r = mysql_query($q);
$count = 0; //counter to limit results shown
while($row = mysql_fetch_assoc($r)){
$thetitle = $row['title']; //result from query
$thetitle = str_replace ("?", "", $thetitle); //remove any question marks from string
$title_array[] = $thetitle; //creating array for query results
$newarray = explode(" ", $search_term); //Seperate user enterd data again
foreach($title_array as $key => $value) {
$thenewarray = explode(" ", $value); //Seperate each result from query
$wordmatch = array_diff_key($thenewarray, array_flip($newarray));
$result = array_intersect($newarray, $wordmatch);
$matchingwords = count($result); //Count the number of matching words from user entered data and the database query
}
if(mysql_num_rows($r)==0)//no result found{
echo "<div id='search-status'>No result found!</div>";
}
else //result found
{
echo "<ul>";
$title = $row['title'];
if ($matchingwords >= 4){
?>
<li><a href='<?php echo $row['url']; ?>'><?php echo $title ?><i> No. matching words: <?php echo $matchingwords; ?></i></a></li>
<?php
$count++;
if ($count == 5) {break;
}
}else{
}
}
echo "</ul>";
}
?>
If you have saved you data in an array you can simply reverse it by using http://www.php.net/manual/en/function.array-reverse.php
Otherwise there are some sort functions
http://php.net/manual/en/function.sort.php
I think you have problem in sorting an array.
If you have an array, sorting is not a matter.
Having different types of sorting found in php.
arsort()
Sort an array in reverse order and maintain index association
http://www.php.net/manual/en/function.asort.php
You can use this array function or let me know your questions briefly.
you can write a own filter function
// sorts an array by direction
function arr_sort($arr, $index, $direction='asc')
{
$i_tab = array();
foreach ($arr as $key => $ele)
{
$i_tab[$key] = $arr[$key][$index];
}
$sort = 'asort';
if (strtolower($direction) == 'desc')
{
$sort = 'arsort';
}
$sort($i_tab);
$n_ar = array();
foreach ($i_tab as $key => $ele)
{
array_push($n_ar, $arr[$key]);
}
return($n_ar);
}
for example you have an array $arr = array('key' => 'value', 'key2' => 'value');
you can now sort by key2 asc with
$arr = arr_sort($old_arr, 'key2', 'desc');
so you can put the total count of matching words into your array as a node for any entry and filter it by it descending
note this requires Mysql version 4+
A fulltext sql query returns values based on relevance.
Example:
SELECT *, MATCH (title)
AGAINST ('$search_term' IN NATURAL LANGUAGE MODE) AS score
FROM posts;
This is how you would implement it
$q = "SELECT *,MATCH (title) AGAINST ('$search_term' IN BOOLEAN MODE) AS relevancy FROM
posts WHERE MATCH (title) AGAINST ('$search_term' IN BOOLEAN MODE) ORDER BY
relevancy DESC";
This will return the posts in order by relevancy. May need to remove the '' around $search_term but you can figure that out with testing.
Please read up on Fulltext sql queries and the match() function. It is all clearly documented.

PHP compare two arrays from different locations

I am wanting to compare two different arrays. Basically I have a database with phrases in and on my website I have a search function where the user types in a phrase.
When they click search I have a PHP page which 'explodes' the string typed in by the user and its put into an array.
Then I pull all the phrases from my database where I have also used the 'explode' function and split all the words into an array.
I now want to compare all the arrays to find close matches with 3 or more words matching each phrase.
How do I do this?
Well what I've tried totally failed, but here is what I have
$search_term = filter_var($_GET["s"], FILTER_SANITIZE_STRING); //user entered data
$search_term = str_replace ("?", "", $search_term); //removes question marks
$array = explode(" ", $search_term); //breaks apart user entered data
foreach ($array as $key=>$word) {
$array[$key] = " title LIKE '%".$word."%' "; //creates condition for MySQL query
}
$q = "SELECT * FROM posts WHERE " . implode(' OR ', $array) . " LIMIT 0,10";
$r = mysql_query($q);
while($row = mysql_fetch_assoc($r)){
$thetitle = $row['title'];
$thetitle = str_replace ("?", "", $thetitle);
$title_array[] = $thetitle;
$newarray = explode(" ", $search_term);
foreach ($newarray as $key=>$newword) {
foreach($title_array as $key => $value) {
$thenewarray = explode(" ", $value);
$contacts = array_diff_key($thenewarray, array_flip($newarray));
foreach($contacts as $key => $value) {
echo $newword."<br />";
echo $value."<br /><hr />";
}
}
}
But basically all I want is to display suggested phrases which are similar to what the user has already typed into the search box.
So If I searched "How do I compare two arrays that have the same values?", I would see 10 suggestions that are worded similar, so like "How to compare multiple arrays?" or "can I compare two arrays" etc...
So basically like when I first posted this question on this site, I got other questions that may help, thats basically what I want. This code im using was origionally to match just one word or an exact matching string, im editing it to find matching words and only show phrases with 3 or more matching words.
I don't think that this is the best solution for your search script. But I'll try to give you the answer:
<?php
$string1 = "This is my first string";
$string2 = "And here is my second string";
$array1 = explode(" ", $string1);
$array2 = explode(" ", $string2);
$num = 0;
foreach($array1 as $arr) {
if(in_array($arr, $array2))
$num++;
}
$match = $num >= 3 ? true : false;
?>
use array_intersect function
$firstArray = "This is a test only";
$secondArray = "This is test";
$array1 = explode(" ", $firstArray);
$array2 = explode(" ", $secondArray);
$result = array_intersect($array1, $array2);
$noOfWordMatch = count($result);
$check = $noOfWordMatch >= 3 ? true : false; ;

How would I sort this array [duplicate]

This question already has an answer here:
Closed 10 years ago.
Possible Duplicate:
How to sort the results of this code?
Im making a search feature which allows a user to search a question and it will show the top 5 best matching results by counting the number of matching words in the question.
Basically I want the order to show the best match first which would be the question with the highest amount of matching words.
Here is the code I have.
<?php
include("config.php");
$search_term = filter_var($_GET["s"], FILTER_SANITIZE_STRING); //User enetered data
$search_term = str_replace ("?", "", $search_term); //remove any question marks from string
$search_count = str_word_count($search_term); //count words of string entered by user
$array = explode(" ", $search_term); //Seperate user enterd data
foreach ($array as $key=>$word) {
$array[$key] = " title LIKE '%".$word."%' "; //creates condition for MySQL query
}
$q = "SELECT * FROM posts WHERE " . implode(' OR ', $array); //Query to select data with word matches
$r = mysql_query($q);
$count = 0; //counter to limit results shown
while($row = mysql_fetch_assoc($r)){
$thetitle = $row['title']; //result from query
$thetitle = str_replace ("?", "", $thetitle); //remove any question marks from string
$title_array[] = $thetitle; //creating array for query results
$newarray = explode(" ", $search_term); //Seperate user enterd data again
foreach($title_array as $key => $value) {
$thenewarray = explode(" ", $value); //Seperate each result from query
$wordmatch = array_diff_key($thenewarray, array_flip($newarray));
$result = array_intersect($newarray, $wordmatch);
$matchingwords = count($result); //Count the number of matching words from
//user entered data and the database query
}
if(mysql_num_rows($r)==0)//no result found
{
echo "<div id='search-status'>No result found!</div>";
}
else //result found
{
echo "<ul>";
$title = $row['title'];
$percentage = '.5'; //percentage to take of search word count
$percent = $search_count - ($search_count * $percentage); //take percentage off word count
if ($matchingwords >= $percent){
$finalarray = array($title => $matchingwords);
foreach( $finalarray as $thetitle=>$countmatch ){
?>
<li><?php echo $thetitle ?><i> <br />No. of matching words: <?php echo $countmatch; ?></i></li>
<?php
}
$count++;
if ($count == 5) {break;
}
}else{
}
}
echo "</ul>";
}
?>
When you search something it will show something like this.
Iv put the number of matching words under each of the questions however they are not in order. It just shows the first 5 questions from the database that have a 50% word match. I want it to show the top 5 with the most amount of matching words.
What code would I need to add and where would I put it in order to do this?
Thanks
Here's my take on your problem. A lot of things have been changed:
mysql_ functions replaced with PDO
usage of anonymous functions means PHP 5.3 is required
main logic has been restructured (it's really hard to follow your result processing, so I might be missing something you need, for example the point of that $percentage)
I realize this might look complicated, but I think that the sooner you learn modern practices (PDO, anonymous functions), the better off you will be.
<?php
/**
* #param string $search_term word or space-separated list of words to search for
* #param int $count
* #return stdClass[] array of matching row objects
*/
function find_matches($search_term, $count = 5) {
$search_term = str_replace("?", "", $search_term);
$search_term = trim($search_term);
if(!strlen($search_term)) {
return array();
}
$search_terms = explode(" ", $search_term);
// build query with bind variables to avoid sql injection
$params = array();
$clauses = array();
foreach ($search_terms as $key => $word) {
$ident = ":choice" . intval($key);
$clause = "`title` LIKE {$ident}";
$clauses []= $clause;
$params [$ident] = '%' . $word . '%';
}
// execute query
$pdo = new PDO('connection_string');
$q = "SELECT * FROM `posts` WHERE " . implode(' OR ', $clauses);
$query = $pdo->prepare($q);
$query->execute($params);
$rows = $query->fetchAll(PDO::FETCH_OBJ);
// for each row, count matches
foreach($rows as $row) {
$the_title = $row->title;
$the_title = str_replace("?", "", $the_title);
$title_terms = explode(" ", $the_title);
$result = array_intersect($search_terms, $title_terms);
$row->matchcount = count($result);
}
// sort all rows by match count descending, rows with more matches come first
usort($rows, function($row1, $row2) {
return - ($row1->matchcount - $row2->matchcount);
});
return array_slice($rows, 0, $count);
}
?>
<?php
$search_term = filter_var($_GET["s"], FILTER_SANITIZE_STRING);
$best_matches = find_matches($search_term, 5);
?>
<?php if(count($best_matches)): ?>
<ul>
<?php foreach($best_matches as $match): ?>
<li><?php echo htmlspecialchars($match->title); ?><i> <br/>No. of matching words: <?php echo $match->matchcount; ?></i></li>
<?php endforeach; ?>
</ul>
<?php else: ?>
<div id="search-status">No result found!</div>
<?php endif; ?>
Try adding asort($finalarray); after your $finalarray = array($title => $matchingwords); declaration:
...
if ($matchingwords >= $percent){
$finalarray = array($title => $matchingwords);
asort($finalarray);
....
It should sort your array Ascending by the Values

Picking numbers in an order

I had a task to slide images from a mysql database using jquery slide and not the animation scripts. The slide is supposed to show at least the most recent ten images that was uploaded. With that I first of all wrote a random query
mysql_query("select * from tblname order by rand() limit 1);
But as expected, it picks the images at random irrespective of when it was posted and of course it wasn't the most recent ten. After some thought I now had to first run a query to get the most recent ten
mysql_query("select * from tblname order by ID limit 10);
while($row=mysql_fetch_array($sql){
$slideid=$slideid.",".$row['recordid'];
}
this of course results to a variable of this order
$var="23,22,24,34,27,78,56,87,98,55";
I tried handling it like an array but it wasn't giving any positive result, hence I had an issue of how to pick this numbers and use it for the slide
$myArr=explode(',',$var);
sort($myArr);
for($i=0;$i<count($myArr);$i++)
{
echo $myArr[$i];
}
Edit: For better efficiency use:
$myArr=explode(',',$var);
sort($myArr);
foreach ($myArr as $val)
{
echo $val;
// Or do whatever else you want with each one.
}
Edit 2: See comments below on efficiency vs for loops vs unexpected results. :)
Based on your comments I will offer my 2p into the mix
this is what I did $slideid="23,22,24,34,27,78,56,87,98,55"; $arr =
explode(',',$slideid); foreach ($arr as $val) { //lets get the
variables from the form post $rs = mysql_query("SELECT * FROM tblname
WHERE id='$val'") or die(mysql_error());
while($row=mysql_fetch_array($rs)){ echo "<img src='image/$image'>"; }
} the images are displayed one by one using jquery slide
Now I think we are wasting time dealing with exploding this variable because mysql has the nifty IN() function (possibly in other db's I don't know)
$slideid = "23,22,24,34,27,78,56,87,98,55";
$rs = mysql_query("SELECT * FROM tblname WHERE id IN({$slideid})") or die(mysql_error());
while ($row = mysql_fetch_assoc($rs))
{
echo "<img src='image/{$row['image']}' />";
}
I hope this helps
$var="23,22,24,34,27,78,56,87,98,55";
$arr = explode(',',$var);
foreach ($arr as $val) {
// work with $val
}
explode splits the string to an array
1) Explode the string into an array, splitting on the comma.
2) You didn't say whether you wanted to re-order the numbers into numerical order, or process them in the order they're already in. If the former, sort the array with sort($arr);
3) Loop over the array in sequence and do something with each number
$str = '1,2,3,4,5,6';
$arr = explode(',', $str);
foreach($arr as $num) echo $num.'<br />';
Note if there is any change of spaces after commas, a better choice would be preg_split rather than explode, as this is more dynamic.
$arr = preg_split('/, ?/', $str);
You can achieve this using php explode function
$pieces = explode(",", $var);
echo $pieces[0]; // piece1
echo $pieces1; // piece2
.
.
.
echo $pieces[n]; // piece n
I think you need to get result of order with respect to order of variable here
$slideid = "23,22,24,34,27,78,56,87,98,55";
$rs = mysql_query("SELECT * FROM tblname WHERE id IN({$slideid}) ORDER BY FIELD(id, {$slideid}) ") or die(mysql_error());
while ($row = mysql_fetch_assoc($rs))
{
echo "<img src='image/{$row['image']}' />";
}

PHP mysql query judge and not echo the repeart part

I want to make a php search query. First, I put a sentence and explode every word get $name,Then I put $name make a query to match all the name which is exist in my database. Then echo part $row['name'][$i] has some word repeat.
for example: the sentence is :Marc Gasol is the brother of Pau Gasol and Gasol in my database, so the match words Gasol apearl 2 times. how to echo $row['name'][$i]; and get only one Gasol? thanks,
$query = mysql_query("SELECT * FROM books WHERE name like '$name[0]' OR name like '$name[1]' OR name like '$name[2]' OR name like '$name[3]' ");
$i = 0;
while($row = mysql_fetch_array($query)) {
echo $row['name'][$i];
$i++;
}
$sentence = "Marc Gasol is the brother of Pau Gasol";
$words = preg_split("/\s+/", $sentence);
//this will uniqueify your value set
$uniqueWords = array_keys(array_flip($words));
foreach($uniqueWords as $word){
$parts[] = "name like '%".mysql_real_escape_string($word)."%'";
}
$where = implode(" OR ", $parts);
$query = mysql_query("SELECT * FROM books WHERE $where ");
$i = 0;
while($row = mysql_fetch_array($query)) {
echo $row['name'][$i];
$i++;
}
You could run another quick loop through your array and remove all duplicate words before you proceed to executing your sql query that way you don't search the name twice in the first place. That should work if I am understanding what you are wanting to do.

Categories