Is this the right way to use Sphinx from PHP? - php

I am just starting with Sphinx. So far I got it installed successfully, got a table called profiles on my MySQL database indexed and am able to get the correct results back using the PHP API. I am using CodeIgniter so I wrapped the default PHP API as a CodeIgniter library.
Anyway this is how my code looks like:
$query = $_GET['q'];
$this->load->library('sphinxclient');
$this->sphinxclient->setMatchMode(SPH_MATCH_ANY);
$result = $this->sphinxclient->query($query);
$to_fetch = array();
foreach($result['matches'] as $key => $match) {
array_push($to_fetch, $key);
}
The array $to_fetch contains the ids of the matched table rows. Now I can use a typical MySQL query to get all the relevant users to display on the search page like so:
$query = 'SELECT * FROM profiles WHERE id IN('. join(',', $to_fetch) . ')';
My question are:
is this the right way to go about it? or is there a default "Sphinx way of doing it" that would be better for performance .
secondly, all I get back at the moment is the id of the matched table rows. I also want the part of the text in the column that matched. For example if a someone searches for the keyword dog and a user on the profiles table had in their about column the following text:
I like dogs. I also like ice cream.
I would like Sphinx to return:
I like <strong>dogs</strong>. I also like ice cream.
How can I do that? I tried to play around with the buildExcerpts() function but can't get it to work.
EDIT
This is how I am getting excerpts now:
// get matched user ids
$to_fetch = array();
foreach($result['matches'] as $key => $match) {
array_push($to_fetch, $key);
}
// get user details of matched ids
$members = $this->search_m->get_users_by_id($to_fetch);
// build excerpts
$excerpts = array();
foreach($members as $member) {
$fields = array(
$member['about'],
$member['likes'],
$member['dislikes'],
$member['occupation']
);
$options = array(
'before_match' => '<strong class="match">',
'after_match' => '</strong>',
'chunk_separator' => ' ... ',
'limit' => 60,
'around' => 3,
);
$excerpt_result = $this->sphinxclient->BuildExcerpts($fields, 'profiles', $query, $options);
$excerpts[$member['user_id']] = $excerpt_result;
}
$excerpts_to_return = array();
foreach($excerpts as $key => $excerpt) {
foreach($excerpt as $v) {
if(strpos($v, '<strong class="match">') !== false) {
$excerpts_to_return[$key] = $v;
}
}
}
As you can see I am searching each query across 4 different mysql columns:
about
likes
dislikes
occupation
Because of this I don't know which of the 4 columns contains the matched keyword. It could be any of them or even more than one. So I have no choice but to run the contents of all 4 columns through the BuildExcerpts() function.
Even then I don't know which one the BuildExcerpts() returned with the <strong class="match"> tags. So I run a stpos check on all values returned by BuildExcerpts() to finally get the proper excerpt and map it to the user whose profile it belongs to.
Do you see a better way than this given my situation where I need to match against the contents of 4 different columns?

Yes that looks good way. One thing to remember the rows coming back from Mysql probably won't be in the order from sphinx.
See the FAQ on sphinx site for how to use FIELD() but personally I like to put the rows from sphinx into associative array, then just loop though the sphinx I'd list and get the row from the array. Avoids a sorting phase altogether at the expense of memory!
As for highlighting, yes do persevere with buildExcerpts - that's is the way to do it.
edit to add, this demo
http://nearby.org.uk/sphinx/search-example5-withcomments.phps
demonstrates both getting rows from mysql and "sorting" in the app. And buildExcerpts.

Related

Simple Dom HTML tags without attributes

Hello I am trying to pull back roster information from ESPN.com. Each team's roster is saved into a table. I am trying to figure a way to save each tag into a variable as appropriate however each tag does not have an ID such as "jersey_number"/"player_name" so search through this has given me some problems. Here is what I have so far - If you could give me a pointer or 2 that would be much appreciated.
<?php
require_once("../tools/simple_html_dom.php");
require_once("../tools/Utilities.php");
$url = "http://espn.go.com/nfl/team/roster/_/name/den/denver-broncos";
$espnHTML = file_get_html("http://espn.go.com/nfl/team/roster/_/name/den/denver-broncos");
foreach($espnHTML->find("table.tablehead",0)->find('tr[class^=odd]') as $rosterRow)
{
foreach($rosterRow->find("td") as $playerInfo)
{
echo $playerInfo->plaintext."<br>";
}
}
?>
How can I assign these td tags into appropriate variables without "ids"? Attached is a sample screenshot that may help you understand what I am talking about.
If the columns are in the same order for every player, using your $rosterrow->find("td") should return an indexed array that you can access using $playerrow[0..n].
Then, by analyzing what corresponds to what you can make a function like this:
$players = array();
foreach($espnHTML->find("table.tablehead",0)->find('tr[class^=odd]') as $rosterRow)
{
$playerRow = $rosterRow->find("td");
$name = $playerRow[0];
$jersey = $playerRow[1];
// more can be added, of course.
$players[$name] = array();
$players[$name]["jersey"] = $jersey;
// and others
}
For table
John Appleseed | 12
---------------|----
Richard Brooks | 34
this will result in an array like
{ "John Appleseed" => { "jersey" => 12 }, "Richard Brooks" => { "jersey" => 34}}
Please let me know if this helped.
If you're open to a different approach that may be more scalable/robust, then you may also want to take a look at Kimono Labs. You can use it to create structured API based on ESPN's data. I think you'd be able to define which part of the table held names, scores, etc. and would easily be able to call the API for the desired info.

String from an array from an array from the database

Okay so, first of all, I searched through the www for this question, and I found some question related to arrays but not exactly to mine.
Okay so as you may know, paypal only allows one custom variable to be $POST but I need to gather the product id AND the quantity of the item bought. So to do this I made my custom variable into something that would get the post like (25-1,12-3,13-4) it means, the user bought 3 items(separated by commas), where the first number is the product id (then the separator '-' comes in) and the second one is the quantity. (so they're all in the same row and column)
Now my problem is displaying it from the database. I need to get the product name and details that's why I need to separate the numbers from each array as a string and fetch the data from the database for the information of the product. (I'm using an older version of php anyway, 5.2, I guess.)Now the problem is:
1.) It returns the word 'Array' (literally) so it would say like ArrayArrayArray
2.) How do I explode/separate those data so I can get it because I need the product ID to fetch some other data... I tried exploding it into array, then exploding it again but doesn't work (most likely my code is wrong?)
Here is my code: (I've already connected to the database)
$data = mysql_query("SELECT * from transactions") or die(mysql_error());
/* My table tag and headers goes here */
while($info = mysql_fetch_array( $data )) {
echo "<tr>";
echo '<td>' . $info['id'] . '</td>';
echo "<td>";
$array = $info['product_id_array'];
$explode_array = explode(",", $array);
foreach($explode_array as $explode_more){
$explode_more = explode("-", $explode_array);
$prod_id = $explode_more[0];
$quantity = $explode_more[1];
print_r($prod_id); //should echo the 25 in the array (25-1), right?
print_r($quantity);
}
echo"</td>";
echo"<tr>";
}
If only paypal would allow multiple custom variables T_T Thank you guys. Forgive me if I can't express my question very well or my language is not good, as english is not my first language :), Good day!
Your variable names are mixed up. Inside the foreach-loop, you should do something like this
foreach($explode_array as $explode_more){
$explode_even_more = explode("-", $explode_more);
$prod_id = $explode_even_more[0];
$quantity = $explode_even_more[1];
print_r($prod_id); //should echo the 25 in the array (25-1), right?
print_r($quantity);
}
Note, that $explode_more is used inside the loop and $explore_array is left as is.
Separate this in multiple tables, never store non-atomic values in 1 column.
Certainly not when they have relation with another table.
Suppose you want to know the sales from a certain product in some period.

Grab Lists from Database then Grab Top Tags In Each List

So, let's say I have a database where users can add "tags" that PHP turns into a comma separated list. The user puts in 'Orange, Peppers, Biscuits Onions Grapes' and It turns into 'orange,peppers,biscuits,onions,grapes'. Now, I'm pretty sure that will be easy enough, and I don't need help there. But now these "tags" are listed in the SQL Database.
$individuallist = $databaserow['database_list'];
$arrayoflist = explode(',', $individuallist );
foreach($arrayoflist as $individualtag) {
//Display Tags
}
So, good, I can grab these tags and use them for the specific item they relate to and I can take the list and turn it into an array and foreach them to display each individual one.
However, I need to take all the lists in the database and add them together. For example:
while($databaserow = mysql_fetch_assoc($databaseresult)) {
$database_array[] = $databaserow ['database_list'];
}
So these two example lists will be combined into an array
// The Two Lists
// 'orange,peppers,biscuits,onions,grapes'
// 'peppers,orange,market,turkey,juice'
$database_full_list = implode(',', $database_array);
// The Full List
// 'orange,peppers,biscuits,onions,grapes,peppers,orange,market,turkey,juice'
Now that I have the full list of tags, I need to count to see which Tags are the Top 30. The idea is that as more tags are added to the database, the Top 30 Tags would be listed in order of how many there are of them.
Orange (2)
Peppers (2)
Bisquits (1)
Market (1)
etc.
I don't know how to this part of the coding.
$split_tags = explode(',', $database_full_list);
$count_tags = array();
foreach($split_tags as $tag) {
if(!array_key_exists($tag, $count_tags))
$count_tags[$tag] = 0;
$count_tags[$tag]++;
}
asort($count_tags);
foreach(array_reverse($count_tags) as $tag => $count)
echo "$tag ($count)<br/>";

How to find #hashtags in strings using Laravel 4.1?

I am currently trying to filter through an Input string to find the single hashtags that a user wants to be displayed with his photo. However, I am currently getting inserts in my database that are not correct.
The best case scenario would be that every single hashtag is saved in a new database row with the photo id. However, I do not really know what to do to accomplish that.
$hashtag = new Hashtag;
$hashtag->photo_id = $photo->id;
$hashtag_string = Input::get('hashtags');
$hashtag_string = Str::contains($hashtag_string, '#')
$hashtag->hashtag = $hashtag_string;
$hashtag->save();
I found some functions in this cheat sheet (http://cheats.jesse-obrien.ca) but I do not get them to work properly.
Try this:
$str = $hashtag_string;
preg_match_all('/#(\w+)/', $str, $matches);
foreach ($matches[1] as $hashtag_name) {
$hashtag = Hashtag::firstOrCreate(array('hashtag' => $hashtag_name));
}
You could then, in this foreach loop, connect those hashtags to a post (or in your case a photo) or sth.

PHP: Most efficient way to display a variable within text when the text could be one of many possibilities

Below is a link to my original question:
PHP: How to display a variable (a) within another variable(b) when variable (b) contains text
Ok here's more to the problem, all your suggestions work but now I'm looking for the most efficient method to my specific problem.
In my database I have several blocks of text. When a user(described as $teamName) logs in to the site, they are randomly assigned one of these blocks of text. Each block of text is different and may have different variables in it.
The problem is I don't have knowledge of which block of text is assigned to the user without actually viewing the database or running a query. So at the moment I have to query the database and select the $newsID that corresponds to the block of text that the user has been assigned.
Because I have preset the blocks of text, I know what they contain so I can know do a switch($newsID) and depending on the value of the $newsID I then run the correct values inserted into the sprintf() function.
There is however, many many blocks of text so there will be many instances of case "": and break;. I wish to have the site working so that if at any stage I change a block of text to something different, then the variables within sprintf() are automatically updated, rather than me manually updating sprintf() within the switch() case:.
Sorry for the long post, hope it makes sense.
EDIT:
I have these predetermined blocks of text in my database in my teamNews table:
For $newsID = 1:
"$teamName is the name of a recently formed company hoping to take over the lucrative hairdryer design
$sector"
For $newsID = 2:
"The government is excited about the potential of ".$teamName.", after they made an annoucement that they have hired $HoM"
For $newsID = 3:
"It is rumored that $teamName are valuing their hairdryer at $salePrice. People are getting excited.
When a user($teamName) logs into the game they are randomly assigned one of these blocks of text with $newsID of 1,2 or 3.
Lets say the user is assigned the block of text with $newsID = 2. So now their username($teamName) is inserted into the database into the same row as their selected text.
Now I want to display the text corresponding to this user so I do the following:
$news = news ($currentStage,$teamName);
switch ($ID)
{
case "1":
sprintf($teamName,$sector)
echo $news."<br/><hr/>";
break;
case "2":
sprintf($teamName,$Hom)
break;
case "3":
sprintf($teamName,$saleprice)
break;
}
$currentStage--;
}
With the function
function news($period,$teamName)
{
$news = mysql_query("
SELECT `content`,`newsID` FROM `teamnews` WHERE `period` = '$period' && `teamName` = '$teamName'
") or die($news."<br/><br/>".mysql_error());
$row = mysql_fetch_assoc($news);
$news = $row['content'];
$ID = $row ['newsID'];
return $news,$ID;
}
The problem is that in reality there are about 20 different blocks of text that the user could be assigned to. So I will have many case:'s.
Also if I want to change all the text blocks in the database I would have to also manually change all the variables in the sprintf's in each ``case:`
I am wondering is there a better way to do this so that if I change the text in the database then the paramaters passed to sprintf will change accordingly.
So if I use
$replaces = array(
'teamName' => 'Bob the team',
'sector' => 'murdering',
'anotherSector' => 'giving fluffy bunnies to children'
);
is it possible to do this:
$replaces = array(
'$teamName' => '$teamName',
'$sector' => '$sector',
'$anotherSector' => '$anothersector'
);
I suggest you have fixed set of named placeholders, and use either the str_replace() or eval() (evil) methods of substitution.
So you would (for example) always have a $teamName and a $sector - and you might only sometimes use $anotherSector. And you have these two strings:
1 - $teamName, is the name of a recently formed company hoping to take over the lucrative $sector.
2 - The people at $teamName hate working in $sector, they would much rather work in $anotherSector
If you were to do:
$replaces = array(
'$teamName' => 'Bob the team',
'$sector' => 'murdering',
'$anotherSector' => 'giving fluffy bunnies to children'
);
$news = str_replace(array_keys($replaces),array_values($replaces),$news);
You would get
1 - Bob the team, is the name of a recently formed company hoping to take over the lucrative murdering.
2 - The people at Bob the team hate working in murdering, they would much rather work in giving fluffy bunnies to children
As long as your placeholders have known names, they don't all have to be present in the string - only the relevant ones will be replaced.
You could create a simple template language, and store templates in your database.
You can use strtr for this.
function replaceTemplateVars($str, $data) {
// change the key format to correspond to the template replacement format
$replacepairs = array();
foreach($data as $key => $value) {
$replacepairs["{{{$key}}}"] = $value;
}
// do the replacement in bulk
return strtr($str, $replacepairs);
}
// store your teamNews table text in this format
// double curly braces is easier to spot and less ambiguous to parse than `$name`.
$exampletemplate = '{{teamName}} is {{sector}} the {{otherteam}}!!'
// get $values out of your database for the user
$values = array(
'teamName' => 'Bob the team',
'sector' => 'murdering',
'otherteam' => 'fluffy bunnies'
);
echo replaceTemplateVars($exampletemplate, $values);
// this will echo "Bob the team is murdering the fluffy bunnies!!"
If you have needs more ambitious than this, such as looping or filters, you should find a third-party php template language and use it.
What about function eval?
http://php.net/eval

Categories