Whats the best way to retrieve information from Sphinx (in PHP)? - php

I'm new to sphinx, and I'm seting it up on a new website.
It's working fine, and when i search with the search in the console, everything work.
Using the PHP api and the searched, gives me the same results as well. But it gives me only ids and weights for the rows found. Is there some way to bring some text fields togheter with the 'matches' hash, for example?
If there is no way to do this, does anyone have a good idea about how to retrieve the records from the database (sql) in the sphinx weight sort order (searching all them at the same time)?

Yeah, sphinx doesn't bring the results.
But I found out a simple way to reorder the query using the IN() clause, to bring all together.
Quering something
SELECT * FROM table WHERE id IN(id_list... )
just indexing the result, with their id in the table:
while ($row = mysql_fetch_objects)
$result[$row->id] = $row;
and having the matching results from sphinx, its very easy to reorder:
$ordered_result = array();
foreach ($sphinxs_results['matches'] as $id => $content)
$ordered_result[] = $result1[$id];
this shall work, if your $sphinxs_results are in the correct order.
its almost pat's answer, but with less one loop. Can make some diference in big results, I guess.

You can use a mysql FIELD() function call in your ORDER BY to ensure everything is in the order sphinx specified.
$idlist = array();
foreach ( $sphinx_result["matches"] as $id => $idinfo ) {
$idlist[] = "$id";
}
$ids = implode(", ", $idlist);
SELECT * FROM table WHERE id IN ($ids) ORDER BY FIELD(id, $ids)

unfortually sphinx didn't returns matched fields, only its ids (sphinx index didn't contains data - only hash from data).
Post about this issue you can find on the sphinxsearch.com forum.

As Alex says, Sphinx doesn't return that information. You will have to use the IDs to query the database yourself - just loop through each ID, get your relevant data out, keeping the results in weighting order. To do it all in one query, you could try something like the following (psuedo-code - PHP ain't my language of choice):
results = db.query("SELECT * FROM table WHERE id IN (%s)", matches.join(", "));
ordered_results = [];
for (match in matches) {
for (result in results) {
if (result["id"] == match) {
ordered_results << result;
}
}
}
return ordered_results;

Related

Get count query results via getSingleScalarResult() and groupBy() - exception

I want get results of my query (with limit 10) + count possible results.
I know there is similar questions and answers.
for example here
but if i trying get count possible rows (via getSingleScalarResult()) i will get excepton: The query returned multiple rows. Change the query or use a different result function like getScalarResult().
$query = $repository
->createQueryBuilder('t')
->select('COUNT(t.katId)', 't.hotel', 't.title', 't.desc', 'picture', 'MIN(t.price) AS price');
$query->where('t.visible = (:visible)')->setParameter('visible', 1);
// + some wheres, where in, more than....
$query->groupBy('t.hotel');
$query->setMaxResults(10);
echo $query->getQuery()->getSingleScalarResult();
exit();
I just need one integer whitch represent all results from my query.
How can i get this count number? Ideal in one shot to db.
EDIT:
if i remove $query->groupBy('t.hotel'); and in select keep only ->select('count(t.katId)'); then it work. But i need groupBy because it makes real count of results.
SOLUTION
I divided it on two queries so - to get results i rolled back changes to state before trying any count information, and make clone this query (before set setMaxResults and groupBy), change select (keep all wheres) and get count information.
I will be grateful if someone offers better solution
Get results:
removed COUNT() from select
asking for results changed to 'normal' ->getArrayResults
Get count:
$q = clone $query;
$q->select('count(distinct t.hotel) as count');
$r = $q->getQuery()->getArrayResult();
echo $r[0]['count'];
exit();
If you need keep the groupBy:
$query = $repository->createQueryBuilder('t')
$query->select('COUNT(t.katId)', 't.hotel', 't.title', 't.desc', 'picture', 'MIN(t.price) AS price');
$query->from(ENTITY STRING, 't', 't.hotel'); //here defined your array result key
$query->where('t.visible = (:visible)')->setParameter('visible', 1);
$query->groupBy('t.hotel');
$query->setMaxResults(10);
echo $query->getQuery()->getScalarResult();
exit();
Edit : New edit works ?
You are only interested in COUNT(t.katId), so you should drop other returned fields 't.hotel', 't.title', etc.
The result will then contain a single return value (single scalar result), so $query->setMaxResults(10) is not needed.

Reading values from mysqli result

I am trying to read an compare values from mysqli query but unsuccessfully.
This is example of my code:
$sql = "SELECT team, won, lost, points, goals_for, goals_agn FROM teaminfo WHERE tour_id=5 ORDER BY points DESC, (goals_for - goals_agn) DESC, goals_for DESC ;";
$query = $this->db_connection->query($sql);
so its simple sql query where I grab all teams from teaminfo DB and I want to compare them according to certain criteria (points, goal scored...) to see which team will go into the next phase of the competition.
Its is simple to print ALL values with something like loop:
while ($team=mysqli_fetch_array($query)) {... some code ...}
But I dont need this. I want to access only few of them and compare them. For example:
//Compare 3rd team points from $query with 4th team points from $query
If ($team[3]['points']==$team[4]['points'])
{
I would do something..
} else ....
I just want "transform" $query so I can use all data from it manually. I tried some stuff from php.net for fetching data but like I said, all was unsuccessfull.
You could put all the data in an array and than work with that.
$teams = array();
while ($team=mysqli_fetch_array($query)) {
$teams[$team['team']] = $team;
}
Then you can access them via $teams['teamname']
if($teams['teamA']['points'] == $teams['teamB']['points']){
// do something
}
its possible to just use
$teams[] = $team;
To fill the array. But I'd recommand an associative filling as that makes it easiert to access the data for a team. With only a numeric entry you'd have to check for their names if you want to use data of specific teams.

How to detect specific keyword from text in a large DB?

I have had at this issue for a day now. From PHP + MYSQL angle. I but because of the amount of data, most all scripts, that I've tried have timed out.
So we have two tables:
People with the row name - about 4000 unique entries
Texts with the row message - about 24 000 entries
Messages have their own format, that names get put into [] tags, like so: [Jenna].
Sadly, not all entries from Texts are correctly formatted. However I do have alot of names in People. So I want to parse trough the Texts->message's and see if any names from People is matched. Of course I do not want to match [Somename], since its already tagged.
Ultimately, the goal is to then do an UPDATE query, so the freshly matched message would be then formatted correctly with [] tag. I don't know if, this could be achieved inside the same single SQL query?!
This is a regex example on, what I want to detect and explanation on what is going on inside preg_match_all(): https://regex101.com/r/cQ6gK5/1
This is what I tried, as advanced MySQL is not my strongest side:
<?
function GetPeople () {
global $DB;
$results = $DB->query("SELECT `name` FROM People");
while ($result = $DB->fetch_array($results)) {
$return[] = $result['name'];
}
return implode('|', $return);
}
$people = GetPeople();
echo '<table><tr><th>Message raw</th><th>Matches</th>';
$results = $DB->query("SELECT `message` FROM Texts WHERE `message` NOT REGEXP '\[(.+?)\]'");
while ($result = $DB->fetch_array($results)) {
if (preg_match_all('/(?:(?:^|[\s])(' . $people . ')[\s|\n])/i', $result['message'], $matches)) {
echo '<tr><td>' . $result['message'] . '</td><td><pre>'; print_r($matches); echo '</pre></td></tr>';
}
}
echo '</table>';
I have indexed out the name and message in MySQL, because I assume, that makes it easier to search. And I imagine, that all this could be done without the php matching and only with SQL query alone. Sadly, I could never get it so optimized as it should be on my own. Any help is highly appreciated, thank you.
You could try something like this:
SELECT texts.message
FROM texts
JOIN people on texts.message LIKE CONCAT('%', people.name, '%');
This will join the two tables and then perform a like comparison based on the 'names' column in the 'people' table.

writing a second query based on results of the first - Not working

*MySQL will be upgraded later.
Preface: Authors can register in two languages and, for various additional reasons, that meant 2 databases. We realize that the setup appears odd in the use of multiple databases but it is more this abbreviated explanation that makes it seem so. So please ignore that oddity.
Situation:
My first query produces a recordset of authors who have cancelled their subscription. It finds them in the first database.
require_once('ConnString/FirstAuth.php');
mysql_select_db($xxxxx, $xxxxxx);
$query_Recordset1 = "SELECT auth_email FROM Authors WHERE Cancel = 'Cancel'";
$Recordset1 = mysql_query($query_Recordset1, $xxxxxx) or die(mysql_error());
$row_Recordset1 = mysql_fetch_assoc($Recordset1);
In the second db where they are also listed, (table and column names are identical) I want to update them because they cancelled. To select their records for updating, I want to take the first recordset, put it into an array, swap out the connStrings, then search using that array.
These also work.
$results = array();
do {
results[] = $row_Recordset1;
} while ($row_Recordset1 = mysql_fetch_assoc($Recordset1));
print_r($results);
gives me an array. Array ( [0] => Array ( [auth_email] => renault#autxxx.com ) [1] => Array ( [auth_email] => rinaldi#autxxx.com ) [2] => Array ( [auth_email] => hemingway#autxxx.com )) ...so I know it is finding the first set of data.
Here's the problem: The query of the second database looks for the author by auth_email if it is 'IN' the $results array, but it is not finding the authors in the 2nd database as I expected. Please note the different connString
require_once('ConnString/SecondAuth.php');
mysql_select_db($xxxxx, $xxxxxx);
$query_Recordset2 = "SELECT auth_email FROM Authors WHERE auth_email IN('$results')";
$Recordset2 = mysql_query($query_Recordset2, $xxxxxx) or die(mysql_error());
$row_Recordset2 = mysql_fetch_assoc($Recordset2);
The var_dump is 0 but I know that there are two records in there that should be found.
I've tried various combinations of IN like {$results}, but when I got to "'$results'", it was time to ask for help. I've checked all the available posts and none resolve my problem though I am now more familiar with the wild goose population.
I thought that since I swapped out the connection string, maybe $result was made null so I re-set it to the original connString and it still didn't find auth_email in $results in the same database where it certainly should have done.
Further, I've swapped out connStrings before with positive results, so... hmmm...
My goal, when working, is to echo the Recordset2 into a form with a do/while loop that will permit me to update their record in the 2nd db. Since the var_dump is 0, obviously this below isn't giving me a list of authors in the second table whose email addresses appear in the $results array, but I include it as example of what I want use to start the form in the page.
do {
$row_Recordset2['auth_email_addr '];
} while($row_Recordset2 = mysql_fetch_assoc($Recordset2));
As always, any pointer you can give are appreciated and correct answers are Accepted.
If you have a db user that has access to both databases and tables, just use a cross database query to do the update
UPDATE
mydb.Authors,
mydb2.Authors
SET
mydb.Authors.somefield = 'somevalue'
WHERE
mydb.Authors.auth_email = mydb2.Authors.auth_email AND
mydb2.Authors.Cancel= 'Cancel'
The IN clause excepts variables formated like this IN(var1,var2,var3)
You should use function to create a string, containing variables from this array.
//the simplest way to go
$string = '';
foreach($results as $r){
foreach($r as $r){
$string .= $r.",";
}
}
$string = substr($string,0,-1); //remove the ',' from the end of string
Its not tested, and obviously not the best way to go, but to show you the idea of your problem and how to handle it is this code quite relevant.
Now use $string instead of $results in query

Using PHP with a MySQL db, how can I select everything from a row if i dont know what the columns are?

I have a table but I dont know what the columns are except for 1 column. There is only 1 permanent data value for each row, the rest of the columns are added and removed elsewhere. This isnt a problem for the query, i just do:
SELECT * FROM table
but for the php function bind_result() i need to give it variables for each column, which i do not know.
I think that once I have the columns in an array, I can do anther query and use call_user_func_array to bind the result to the array.
This seems like it would come up a lot so im wondering is there a standard way of doing this?
Couldn't you just do:
$result = mysql_query("SELECT * FROM table");
while ($row = mysql_fetch_assoc($result))
{
foreach ($row as $field => $value)
{
...
}
}
You could do
show columns from table;
And then parse that string to grab your column names.
You can also try the describe command, which is used to list all of the fields in a table and the data format of each field. Usage:
describe TableName;
you can use
$metadata = $prep_statement->result_metadata()
after you executed the statement and then loop through all result fields using something like
while( $field = $metadata->fetch_field() ) { }
the properties of $field are documented here: http://www.php.net/manual/en/mysqli-result.fetch-field.php

Categories