Search query for multiple search terms - php

I'm running Laravel 5 and have built a small search function:
$q = Input::get('q');
$search_terms = explode(' ', $q);
$user_query = User::select();
$news_query = Article::select();
foreach ($search_terms as $term) {
$user_query->where('username', 'like', '%' . $term . '%');
$news_query->where('title', 'like', '%' . $term . '%');
}
$user_results = $user_query->get();
$news_results = $news_query->get();
return view('search', ['q' => $q, 'user_results' => $user_results, 'news_results' => $news_results]);
It works for one search term, but doesn't quite work with multiple words.
Example:
"boss" returns users and news items that contain "boss"
"boss man" returns users and news items that contain "boss"
"man boss" returns users and news items that contain "man"
How can I make adjustments so it will return users and news items that contain "boss" or "man" ?

Right now, your query is executed using and statements, so MySQL is looking for usernames consisting of both boss and man.
You can change to orWhere() and it should work right away. Here's a quick experiment I did in Tinker using your code:
$terms = explode(' ', 'c a');
$user_query = User::select();
foreach ($terms as $term) {
$user_query->orWhere('username', 'like', '%' . $term . '%');
}
$user_results = $user_query->get();
$user_results->toArray();
// array(
// 0 => array(
// 'id' => 2,
// 'username' => 'christopher',
// 'created_at' => '2014-04-27 18:41:56',
// 'updated_at' => '2014-11-07 13:42:58',
// 'remember_token' => NULL
// ),
// 1 => array(
// 'id' => 4,
// 'username' => 'Kalle',
// 'created_at' => '2014-11-07 13:42:55',
// 'updated_at' => '2014-11-07 13:42:55',
// 'remember_token' => NULL
// )
// )

Related

Laravel Eloquent get Clients which have active jobs

I'm working on a table which should show clients which have active jobs. I've got a page with all clients and this is working. I'm trying to get a query which is conditional on the client having active jobs. So here is what I have in my dataSource function:
public function dataSourcejobs(Request $request) {
$search = $request->query('search', array('value' => '', 'regex' => false));
$draw = $request->query('draw', 0);
$start = $request->query('start', 0);
$length = $request->query('length', 25);
$order = $request->query('order', array(0, 'desc'));
$filter = $search['value'];
$sortColumns = array(
0 => 'id',
1 => 'client',
2 => 'active_jobs',
3 => 'is_enabled',
4 => 'actions'
);
$query = Client::select( 'clients.*' );
if (!empty($filter)) {
$query->where( 'title', 'like', '%'.$filter.'%' );
}
$recordsTotal = $query->count();
$sortColumnName = $sortColumns[$order[0]['column']];
$query->orderBy($sortColumnName, $order[0]['dir'])
->take($length)
->skip($start);
$json = array(
'draw' => $draw,
'recordsTotal' => $recordsTotal,
'recordsFiltered' => $recordsTotal,
'data' => [],
);
$clients = $query->get();
foreach ($clients as $client) {
// Get active jobs for this client.
$jobs = Job::where( 'client_id', $client->id )->where('is_active', 1)->get();
$json['data'][] = [
$client->id,
$client->title,
'<button class="jobs">' . count($jobs) . ' Jobs</button>',
( $client->is_enabled === 1 ) ? 'Yes' : 'No',
'' . config( 'ecl.EDIT' ) . ' ' . config( 'ecl.WORK' ) . ''
];
}
return $json;
}
I've tried to do things like $query = Client::select( 'clients.*' )->count($client->jobs); but this is obviously wrong and errors. I also tried to do this in the loop (by checking the count) but this obvoiusly broke how the pagination works (but did show only clients with active jobs)
I should point out that the function above shown all clients even the ones which have no associated active jobs.
thanks
to get the count along with each client you can use withCount refer to this link https://laravel.com/docs/9.x/eloquent-relationships#counting-related-models
like the following
$query = Client::withCount('jobs');
as for getting the clients who only have jobs you can use whereHas

Solr FieldCollapsing for More Like This queries

I want to use a "More Like This" query to find similar documents and collapse those that have the same value for the field 'image'. I tried to use the Field Collapsing parameters however they do not seem to work for "More like this".
Below is a snippet of my code. Can you tell me how to collapse results using the "More Like This" query?
$url = "http://{$host}:{$port}/solr/{$core}/mlt";
$data = [
'stream.body' => $content,
'fl' => 'image,content,title,signature',
'start' => 0,
'order' => "score desc",
'wt' => 'json',
'mlt.fl' => 'content,title',
// these lines do nothing ---v
'group' => 'true',
'group.field' => 'image',
'group.sort' => 'impressions desc',
'group.main' => 'true'
];
$curlHandle = curl_init($url);
$options = array (
CURLOPT_POST => 1,
CURLOPT_POSTFIELDS => $data
);
curl_setopt_array($curlHandle , $options);
$result = json_decode(curl_exec($curlHandle));
General answer
I could not collapse results using Field Collapsing paramaters. However, I was able to achieve the desired result using CollapsingQParserPlugin.
The following filter query collapses documents on the field 'image' and selects the one with the highest value for the field 'impressions': {!collapse field=image max=impressions}
Implementation
For some reason I was not able to combine this filter query with my other filter queries under a single key as follows:
$filterQueries = [
"-signature:{$signature}",
...
"{!collapse field=image max=impressions}"
];
$data = [
...
'fq' => implode(' AND ', $filterQueries),
...
];
This produced the error: Query does not implement createWeight
My fix was to do a GET request (instead of a POST, which was done in the question above). With the GET request it is possible to have a key for each filter query: http://solr-url/mtl?...&fq=-signature%3A0&...&fq=%7B!collapse+field%3Dimage+max%3Dimpressions%7D
Below is the php solution for the snippet in the question:
$url = "http://{$host}:{$port}/solr/{$core}/mlt?"; // Note the added question mark
$data = [
'stream.body' => $content,
'fl' => 'image,content,title,signature',
'fq' => $filterQueries,
'start' => 0,
'order' => "score desc",
'wt' => 'json',
'mlt.fl' => 'content,title'
];
$params = [];
foreach ($data as $key=>$value) {
if (is_array($value)) {
foreach ($value as $subvalue) {
$subvalue = urlencode($subvalue);
$params[] = "{$key}={$subvalue}";
}
} else {
$value = urlencode($value);
$params[] = "{$key}={$value}";
}
}
$url .= implode('&', $params);
$curlHandle = curl_init($url);
$options = array ();
curl_setopt_array($curlHandle , $options);
$result = json_decode(curl_exec($curlHandle));

Multiple OR conditions in CakePHP v1.3.15

I have issues with OR conditions in cake php query builder. This will return 0 result.
$results = $this->paginate('Did', array('Did.ivr_id LIKE ' => $number . "%",'OR'=>array('Did.did LIKE ' => $number . "%")));
$result = $this->paginate = array(array('Did.did LIKE' => $number . "%"));
$this->set('dids', $results);
When i apply condition on simple column it gives accurate result
$results = $this->paginate('Did', array('Did.ivr_id LIKE' => $number . "%"));
$result = $this->paginate = array(array('Did.did LIKE' => $number . "%"));
$this->set('dids', $results);
You need to put all the conditions that you want to OR inside the OR array.
$results = $this->paginate(
'Did',
array(
'OR'=>array(
'Did.ivr_id LIKE ' => $number . "%",
'Did.did LIKE ' => $number . "%"
)
)
);

Sphinx search - Search with booleans

Please excuse my bas english, i'm french !
I want to integrate Sphinx search in my website, but I've got one or two questions !
So, I've got a clothes ecommerce website (with codeigniter) and every article have those params : id, title, categoryName, size, brand, description, isDeleted, isSold, etc.
When I made a search with a boolean, it is ignored ! So can you say me how can I filter deleted and sold articles (isDeleted and isSold field) ?
Here my code
function sphinx_search($fields, $order_by, $order_order, $position, $offset, $limit){
$CI =& get_instance();
$CI->load->library('SphinxClient');
$ids = array();
$CI->sphinxclient->SetServer("localhost" , 9312);
$CI->sphinxclient->SetMatchMode(SPH_MATCH_ANY);
$CI->sphinxclient->SetFieldWeights(array('title' => 300, 'categoryName' => 200, 'size' => 150, 'brand' => 100, 'description' => 30));
$CI->sphinxclient->SetLimits($offset, $limit);
$CI->sphinxclient->SetSortMode(SPH_SORT_EXTENDED, $order_by.' '.$order_order);
if (!empty($position)) {
$CI->sphinxclient->SetGeoAnchor('latitude', 'longitude', (float) deg2rad($position['latitude']), (float) deg2rad($position['longitude']));
$CI->sphinxclient->setSelect("*, IF(#geodist<50000,30,0)+IF(#geodist<20000,80,0)+IF(#geodist<5000,150,0)+#weight AS performance");
}
$query='';
foreach ($fields as $key => $value) {
if ($key == 'q') {
$query .= ' '.$value.' ';
} else {
$query .= ' #'.$key.' '.$value.' ';
}
}
$result = $CI->sphinxclient->Query( $query, 'catalog' );
if ( $result === false )
var_dump('[SPHINX]Query failed: ' . $CI->sphinxclient->GetLastError());
elseif ( $CI->sphinxclient->GetLastWarning() )
var_dump('[SPHINX]WARNING: ' . $CI->sphinxclient->GetLastWarning());
if ( !empty($result["matches"]) ){
foreach ( $result["matches"] as $doc => $docinfo )
$ids[] = $doc;
} else {
return false;
}
return array( 'ids' => $ids, 'total' => $result['total'], 'docs' => count($result["matches"]) );
}
Thanks.
You should define the booleans as attributes in the config file.
Then can use SetFilter function to, well, filter on them :)

Fetch array using both if and while doesn't work

Basically I have 2 methods in the same class, getMovie and getGenres. They are very similar but One doesn't return what I expect.
Here's getMovie method:
public function getMovie($argType, $arg){
$movieQuery = "SELECT id,
rt_id,
imdb_id,
url,
rt_url,
type,
adult,
DATE_FORMAT(release_date, '%Y') AS year,
date_added,
title,
runtime,
budget,
revenue,
homepage,
rating,
tagline,
overview,
popularity,
image,
backdrop,
trailer
FROM movies
WHERE " . $argType . " = " . $arg;
$movieResult = $this->_query($movieQuery);
$movies = array();
if($movieResult->fetch_array(MYSQLI_ASSOC)){
while($m = $movieResult->fetch_array(MYSQLI_ASSOC)){
$movies[] = array( 'title' => $m['title'],
'duplicate' => $m['duplicate'],
'url' => $m['url'],
'rt_url' => $m['rt_url'],
'release_date' => $m['release_date'],
'date_added' => $m['date_added'],
'type' => 'movie',
'adult' => $m['adult'],
'id' => $id,
'rt_id' => $m['rt_id'],
'imdb_id' => $m['imdb_id'],
'rating' => $m['rating'],
'tagline' => $m['tagline'],
'overview' => $m['overview'],
'popularity' => $m['popularity'],
'runtime' => $m['runtime'],
'budget' => $m['budget'],
'revenue' => $m['revenue'],
'homepage' => $m['homepage'],
'image' => $m['image'],
'backdrop' => $m['backdrop'],
'trailer' => $m['trailer'] );
}
return $movies;
}
else{
return false;
}
Here's getGenres method:
public function getGenres($movieId = NULL){
$genresQuery = "";
if($movieId != NULL){
$genresQuery = "SELECT id,
name
FROM genres
WHERE id = ANY (
SELECT genre_id
FROM movie_genres
WHERE movie_id = " . $movieId . ")";
}
else{
$genresQuery = "SELECT id,
name
FROM genres";
}
$genresResult = $this->_query($genresQuery);
$genres = array();
if($genresResult->fetch_array(MYSQLI_ASSOC)){
while($genre = $genresResult->fetch_array(MYSQLI_ASSOC)){
$genres[] = array( 'id' => $genre['id'],
'name' => $genre['name'] );
}
return $genres;
}
else{
return false;
}
}
And here's how I call them:
$mov = $movie->getMovie(2207);
print_r($mov); // output: Array()
$gen = $movie->getGenres(2207);
print_r($gen); // output: Array(values inside)
Both queries do actually return expected values but getMovies method doesn't work with the if statement. It works fine if I just have while loop.
I am using if as well as while as I heard that while loop can sometimes execute even when there's not values. Is there any truth to this? If there is indeed a reason to use an if statement as well as wile loop then why doesn't it work with getMovies method?
Edit 1: I tried storing the array like so but that resulted in a memory related error:
$r = $genresResult->fetch_array(MYSQLI_ASSOC);
if($r){
while($r){
$genres[] = array( 'id' => $genre['id'],
'name' => $genre['name'] );
}
return $genres;
}
I am using if as well as while as I heard that while loop can sometimes execute even when there's not values. Is there any truth to this?
No, according to the php manual mysqli_result::fetch_array returns an array of strings that corresponds to the fetched row or NULL if there are no more rows in resultset.
Null is falsy so the while loop will not be entered.
Although the if statement is unnecessary if you had one you would use mysqli_result::$num_rows to check if the query returned any rows.
if($movieResult->num_rows > 0){
while($m = $movieResult->fetch_array(MYSQLI_ASSOC)){
...
}
}

Categories