Ignore:
Timestamp:
09/24/12 22:50:24 (7 years ago)
Author:
rvelices
Message:

quick search - better handling of wildcard begin/end in tag names (technically rewrote parts of query analser)
still to do: exclusion of matching tags

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/include/functions_search.inc.php

    r17748 r18207  
    272272} 
    273273 
     274function is_odd_wbreak_begin($ch) 
     275{ 
     276  return strpos('[{<=*+', $ch)===false ? false:true; 
     277} 
     278 
     279function is_odd_wbreak_end($ch) 
     280{ 
     281  return strpos(']}>=*+', $ch)===false ? false:true; 
     282} 
     283 
     284define('QST_QUOTED',   0x01); 
     285define('QST_NOT',      0x02); 
     286define('QST_WILDCARD_BEGIN',0x04); 
     287define('QST_WILDCARD_END',  0x08); 
     288define('QST_WILDCARD', QST_WILDCARD_BEGIN|QST_WILDCARD_END); 
     289 
     290 
    274291/** 
    275292 * analyzes and splits the quick/query search query $q into tokens 
     
    284301  $token_modifiers = array(); 
    285302  $crt_token = ""; 
    286   $crt_token_modifier = ""; 
    287   $state = 0; 
     303  $crt_token_modifier = 0; 
    288304 
    289305  for ($i=0; $i<strlen($q); $i++) 
    290306  { 
    291307    $ch = $q[$i]; 
    292     switch ($state) 
    293     { 
    294       case 0: 
     308    if ($crt_token_modifier&QST_QUOTED==0) 
     309    { 
    295310        if ($ch=='"') 
    296311        { 
    297           $tokens[] = $crt_token; $token_modifiers[] = $crt_token_modifier; 
    298           $crt_token = ""; $crt_token_modifier = "q"; 
    299           $state=1; 
    300         } 
    301         elseif ( $ch=='*' ) 
    302         { // wild card 
     312          if (strlen($crt_token)) 
     313          { 
     314            $tokens[] = $crt_token; $token_modifiers[] = $crt_token_modifier; 
     315            $crt_token = ""; $crt_token_modifier = 0; 
     316          } 
     317          $crt_token_modifier |= QST_QUOTED; 
     318        } 
     319        elseif ( strcspn($ch, '*+-><~')==0 ) 
     320        { //special full text modifier 
    303321          if (strlen($crt_token)) 
    304322          { 
     
    307325          else 
    308326          { 
    309             $crt_token_modifier .= '*'; 
    310           } 
    311         } 
    312         elseif ( strcspn($ch, '+-><~')==0 ) 
    313         { //special full text modifier 
    314           if (strlen($crt_token)) 
    315           { 
    316             $tokens[] = $crt_token; $token_modifiers[] = $crt_token_modifier; 
    317             $crt_token = ""; $crt_token_modifier = ""; 
    318           } 
    319           $crt_token_modifier .= $ch; 
     327            if ( $ch=='*' ) 
     328              $crt_token_modifier |= QST_WILDCARD_BEGIN; 
     329            if ( $ch=='-' ) 
     330              $crt_token_modifier |= QST_NOT; 
     331          } 
    320332        } 
    321333        elseif (preg_match('/[\s,.;!\?]+/', $ch)) 
     
    324336          { 
    325337            $tokens[] = $crt_token; $token_modifiers[] = $crt_token_modifier; 
    326             $crt_token = ""; $crt_token_modifier = ""; 
    327           } 
     338            $crt_token = ""; 
     339          } 
     340          $crt_token_modifier = 0; 
    328341        } 
    329342        else 
     
    331344          $crt_token .= $ch; 
    332345        } 
     346    } 
     347    else // qualified with quotes 
     348    { 
     349      if ($ch=='"') 
     350      { 
     351        if ($i+1 < strlen($q) && $q[$i+1]=='*') 
     352        { 
     353          $crt_token_modifier |= QST_WILDCARD_END; 
     354          $i++; 
     355        } 
     356        $tokens[] = $crt_token; $token_modifiers[] = $crt_token_modifier; 
     357        $crt_token = ""; $crt_token_modifier = 0; 
     358        $state=0; 
    333359        break; 
    334       case 1: // qualified with quotes 
    335         switch ($ch) 
    336         { 
    337           case '"': 
    338             $tokens[] = $crt_token; $token_modifiers[] = $crt_token_modifier; 
    339             $crt_token = ""; $crt_token_modifier = ""; 
    340             $state=0; 
    341             break; 
    342           default: 
    343             $crt_token .= $ch; 
    344         } 
    345         break; 
     360      } 
     361      else 
     362        $crt_token .= $ch; 
    346363    } 
    347364  } 
     
    383400  { 
    384401    $token = trim($tokens[$i], '%'); 
    385     if (strstr($token_modifiers[$i], '-')!==false) 
     402    if ($token_modifiers[$i]&QST_NOT) 
    386403      continue; 
    387404    if ( strlen($token)==0 ) 
     
    422439    ); 
    423440  $q = trim($q); 
    424   if (empty($q)) 
     441  analyse_qsearch($q, $tokens, $token_modifiers); 
     442  if (count($tokens)==0) 
    425443  { 
    426444    return $search_results; 
    427445  } 
     446  $debug[] = '<!--'.count($tokens).' tokens'; 
    428447   
    429   analyse_qsearch($q, $tokens, $token_modifiers); 
    430  
    431448  $q_like_field = '@@__db_field__@@'; //something never in a search 
    432449  $q_like_clause = get_qsearch_like_clause($tokens, $token_modifiers, $q_like_field ); 
     
    468485    } 
    469486  } 
     487  $debug[] = count($by_weights).' fulltext'; 
     488  $debug[] = 'ft score min:'.min($by_weights).' max:'.max($by_weights); 
    470489 
    471490 
     
    494513    for ($i=0; $i<count($tokens); $i++) 
    495514    { 
    496       if (strstr($token_modifiers[$i], '-')!==false) 
     515      if ($token_modifiers[$i]&QST_NOT) 
    497516        continue;// ignore this NOT token 
    498517      $transliterated_token = $transliterated_tokens[$i]; 
     
    502521      while ( ($pos = strpos($transliterated_tag, $transliterated_token, $pos)) !== false) 
    503522      { 
    504         if (strstr($token_modifiers[$i], '*')!==false) 
     523        if ( ($token_modifiers[$i]&QST_WILDCARD)==QST_WILDCARD ) 
    505524        {// wildcard in this token 
    506525          $match = 1; 
     
    509528        $token_len = strlen($transliterated_token); 
    510529 
    511         $word_begin = $pos; 
    512         while ($word_begin>0) 
     530        // search begin of word 
     531        $wbegin_len=0; $wbegin_char=' '; 
     532        while ($pos-$wbegin_len > 0) 
    513533        { 
    514           if (! is_word_char($transliterated_tag[$word_begin-1]) ) 
     534          if (! is_word_char($transliterated_tag[$pos-$wbegin_len-1]) ) 
     535          { 
     536            $wbegin_char = $transliterated_tag[$pos-$wbegin_len-1]; 
    515537            break; 
    516           $word_begin--; 
    517         } 
    518  
    519         $word_end = $pos + $token_len; 
    520         while ($word_end<strlen($transliterated_tag) && is_word_char($transliterated_tag[$word_end]) ) 
    521           $word_end++; 
    522  
    523         $this_score = $token_len / ($word_end-$word_begin); 
    524         if ($token_len <= 2) 
    525         {// search for 1 or 2 characters must match exactly to avoid retrieving too much data 
    526           if ($token_len != $word_end-$word_begin) 
    527             $this_score = 0; 
    528         } 
    529         elseif ($token_len == 3) 
     538          } 
     539          $wbegin_len++; 
     540        } 
     541 
     542        // search end of word 
     543        $wend_len=0; $wend_char=' '; 
     544        while ($pos+$token_len+$wend_len < strlen($transliterated_tag)) 
    530545        { 
    531           if ($word_end-$word_begin > 4) 
    532             $this_score = 0; 
     546          if (! is_word_char($transliterated_tag[$pos+$token_len+$wend_len]) ) 
     547          { 
     548            $wend_char = $transliterated_tag[$pos+$token_len+$wend_len]; 
     549            break; 
     550          } 
     551          $wend_len++; 
     552        } 
     553 
     554        $this_score = 0; 
     555        if ( ($token_modifiers[$i]&QST_WILDCARD)==0 ) 
     556        {// no wildcard begin or end 
     557          if ($token_len <= 2) 
     558          {// search for 1 or 2 characters must match exactly to avoid retrieving too much data 
     559            if ($wbegin_len==0 && $wend_len==0 && !is_odd_wbreak_begin($wbegin_char) && !is_odd_wbreak_end($wend_char) ) 
     560              $this_score = 1; 
     561          } 
     562          elseif ($token_len == 3) 
     563          { 
     564            if ($wbegin_len==0) 
     565              $this_score = $token_len / ($token_len + $wend_len); 
     566          } 
     567          else 
     568          { 
     569            $this_score = $token_len / ($token_len + 1.1 * $wbegin_len + 0.9 * $wend_len); 
     570          } 
    533571        } 
    534572 
     
    547585  } 
    548586  $search_results['qs']['matching_tags']=$all_tags; 
     587  $debug[] = count($all_tags).' tags'; 
    549588 
    550589  // Step 2.2 - reduce matching tags for every token in the query search 
     
    573612    foreach($token_tags[$i] as $arr) 
    574613      $tag_ids[] = $arr['tag_id']; 
     614    $tag_ids = array_unique($tag_ids); 
     615    $debug[] = count($tag_ids).' unique tags'; 
    575616 
    576617    if (!empty($tag_ids)) 
    577618    { 
     619      $tag_photo_count=0; 
    578620      $query = ' 
    579621SELECT image_id 
     
    586628        $image_id=(int)$row['image_id']; 
    587629        @$by_weights[$image_id] += 1; 
    588       } 
     630        $tag_photo_count++; 
     631      } 
     632      $debug[] = $tag_photo_count.' photos for tags'; 
     633      $debug[] = count($by_weights).' photos after tags'; 
    589634    } 
    590635  } 
     
    612657    } 
    613658  } 
     659  $debug[] = count(@$search_results['qs']['matching_cats']).' albums with images'; 
    614660 
    615661  if ( empty($by_weights) and empty($search_results['qs']['matching_cats']) ) 
     
    655701  $allowed_images = array_from_query( $query, 'id'); 
    656702 
     703  $debug[] = count($allowed_images).' final photo count -->'; 
     704  global $template; 
     705  $template->append('footer_elements', implode(', ', $debug) ); 
     706 
    657707  if ( $super_order_by or empty($by_weights) ) 
    658708  { 
Note: See TracChangeset for help on using the changeset viewer.