我有一个有点复杂的搜索查询,我希望提高效率(如果可能的话)。
以下是此查询的完整代码:
Route::post('api/search/{startRow}', function($startRow)
{
$category = Category::where('name', '=', Input::get('category'))->first();
// Initialize query
$query = Resource::with('alerts', 'alerts.type', 'user', 'category', 'comments', 'comments.comments', 'ratings')
->where('duplicate', '=', 0);
// Limit search results
if(Input::get('show'))
{
$show = Input::get('show');
switch ($show) {
case 'verified':
$query->where('verified', '=', true);
break;
case 'unverified':
$query->where('verified', '=', false);
break;
case 'alerted':
$query->has('alerts');
break;
case 'unalerted':
$query->has('alerts', '=', 0);
break;
default:
// The default will be 'all' (show all results)
break;
}
}
if($category->name != "everything")
$query->where('category_id', '=', $category->id);
// Sort the search results
if(Input::get('sort_type'))
{
$sort_by = Input::get('sort_type');
switch ($sort_by)
{
case 'relevance':
break;
case 'name_asc':
$query->orderBy('name', 'asc');
break;
case 'name_desc':
$query->orderBy('name', 'desc');
break;
case 'rating_high':
$query
->leftJoin('ratings', 'ratings.ratable_id', '=', 'resources.id')
->where('ratings.ratable_type', '=', 'Resource')
->orderBy(DB::raw('avg(ratings.score)'), 'desc')
->orderBy(DB::raw('count(ratings.score)'), 'desc')
->select('resources.*')
->groupBy('resources.id');
break;
case 'rating_low':
$query
->leftJoin('ratings', 'ratings.ratable_id', '=', 'resources.id')
->where('ratings.ratable_type', '=', 'Resource')
->orderBy(DB::raw('avg(ratings.score)'), 'asc')
->orderBy(DB::raw('count(ratings.score)'), 'asc')
->select('resources.*')
->groupBy('resources.id');
break;
case 'date_new':
$query->orderBy('created_at', 'desc');
break;
case 'date_old':
$query->orderBy('created_at', 'asc');
break;
default:
break;
}
}
// Search by keyword(s)
if(Input::get('keyword'))
{
$search = Input::get('keyword');
$searchTerms = explode(' ', $search);
$fields = array(
'resources.description',
'resources.website',
'resources.additional_info');
foreach ($searchTerms as $term)
{
$query->where('resources.name', 'LIKE', '%'. $term .'%');
foreach ($fields as $field)
{
$query->orWhere($field, 'LIKE', '%'. $term .'%');
}
}
}
// Search by tag(s)
if(Input::get('tags'))
{
$tags = Input::get('tags');
$query
->select('resources.*')
->join('taggables', 'taggables.taggable_id', '=', 'resources.id')
->join('tags', 'taggables.tag_id', '=', 'tags.id')
->whereIn('tags.id', $tags)
->groupBy('resources.id')
->havingRaw('COUNT(resources.id)=?', array(count($tags)));
}
// Total number of results
$count = $query->get()->count();
// Page number and offset for infinite scroll
$query->skip($startRow)->take(10);
// Get our first set of tiles
$tiles = $query->get();
return Response::json(array(
'count' => $count,
'tiles' => $tiles->toArray()));
});
你知道,我有一个充满“资源”的数据库(通过数据透视表)与标签,评论和警报相关,我希望这些资源可以按以下任何条件进行搜索: 资源模型本身包含的文本,与资源关联的标记以及关联警报的数量。
我遇到的一个问题是关键字搜索似乎不够“准确”。当我搜索“Venture Firm”时,在包含“Venture Firm”这一短语之前返回了一些结果 - 用户绝对不会期望这样。
我遇到的另一个问题是选择“show”类型(例如$query->has('alerts')
,如果用户只想查看带有警报的资源)。如果我输入关键字搜索和显示类型(如上所述),结果仍将包含没有警报的资源(即使我指定我只需要具有警报的资源)。
答案 0 :(得分:1)
相关性搜索取决于您的数据库引擎。
但是对于关键字搜索,你错了:
foreach ($fields as $field)
{
$query->orWhere($field, 'LIKE', '%'. $term .'%');
}
这篇文章增加了WHERE ....long list of clauses here.... OR something LIKE %term% ...
什么基本上打破了整个事情。
相反,你需要这个:
$fields = array(
'resources.name',
'resources.description',
'resources.website',
'resources.additional_info'
);
$query->where(function ($q) use ($searchTerms, $fields) {
foreach ($searchTerms as $term)
{
foreach ($fields as $field)
{
$q->orWhere($field, 'LIKE', '%'. $term .'%');
}
}
});
这会将OR .. OR ..
条款包含在AND ( .. OR .. )
。