2014-08-29 4 views
0

필자는 다소 복잡한 회선 검색 쿼리를 사용하여 가능한 한 효율적으로 만들고 싶습니다. 여기 이 검색 쿼리를보다 효율적으로 만들 수 있습니까?

이 쿼리에 대한 전체 코드입니다 :

는 "자원"(피벗 테이블을 통해) 가득 데이터베이스가 태그, 코멘트 및 경고와 관련된 볼
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"이라는 문구가 들어가기 전에 몇 가지 결과가 반환됩니다. 사용자는 확실히 이것을 예상하지 않을 것입니다.

또 다른 문제 "표시 유형"(즉, 사용자가 알림이있는 리소스 만보고 싶다면 $query->has('alerts'))을 선택하는 것과 관련되어 있습니다. 위와 같이 키워드 검색 및 프로그램 유형을 입력하면 검색 결과에는 경고가없는 리소스가 포함됩니다 (알림이있는 리소스 만 필요함).

답변

1

관련성 검색은 db 엔진에 따라 다릅니다.

그러나 키워드 검색

, 당신은 잘못이 있습니다

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 .'%'); 
    } 
    } 
}); 

AND (.. OR ..)OR .. OR .. 절을 포장합니다

대신 당신이 필요합니다.

+0

감사합니다. - 도움이되었습니다. [http://laravel.com/docs/queries#advanced-wheres](http://laravel.com/docs/queries#advanced-wheres)를 보는 것도 유용했습니다. 코드에 몇 가지 구문 오류가 있지만 이해합니다. – chipit24

+0

@ cornflakes24 필자는'$ q'와'$ query'와는 별개로 거기에 구문 오류가 없다고 생각합니다. 잘못 입력했거나 괄호가 누락되었습니다. 이것이 당신이 의미하는 것이라고 가정합니다. –

+0

네, 그게 제가 의미했던 것입니다! 나는'$ q'와'$ query'와의 혼동은 의미 론적 오류가 될 것이고 누락 된 괄호는 구문 오류가 될 것이라고 생각합니까? – chipit24

관련 문제