Forum for discussing general topics related to Couch.
13 posts Page 1 of 2
I am reading this article:
http://www.askingbox.com/tip/mysql-comb ... -3-letters

do you guys thinks this this a possible solution for mysql fulltext search? Can I alter couch search code to something like this?

I'm sorry but I really not a php or mysql expert....
Perhaps we can get it to work but, in case you did not notice, the given solution will *not* work for words *less* than 3 characters in length - it will only add words of *exactly* the length of 3 to the current search setup.

So the limitation of length will possibly go down from the current 4 to 3 but no further.

Do you think that would be fine for your needs?
Please let me know.
Yes, I think it will make the current search function become really really useful...

example, I have product terms that included something like "max" "mix" "ply", terms like this...

Perhaps we can get it to work but, in case you did not notice, the given solution will *not* work for words *less* than 3 characters in length - it will only add words of *exactly* the length of 3 to the current search setup.


Is this mean that it can search the word that more equal and more than 3? I noticed in the php code, it has set the limitation character to "3", is it possible to make it 2? It will be easier to let the user search for 2 characters' product code.

But if you think is no possible, then I think 3 characters solution will just fine for now.

Here is my suggestion for couch search function, after you complete with the search code, the couch user can adjust the character length, maybe at "config" file, something like "search_min_length=2". by the way, just a suggestion....

Another problem, how to let it show message, when the character is less than 3 or 4? For now, I am using:
Code: Select all
<cms:no_results>
      <h3>No pages found</h3>
   </cms:no_results>


I want it to display message "The product code is too short".
nsy wrote: Yes, I think it will make the current search function become really really useful...

example, I have product terms that included something like "max" "mix" "ply", terms like this...

Perhaps we can get it to work but, in case you did not notice, the given solution will *not* work for words *less* than 3 characters in length - it will only add words of *exactly* the length of 3 to the current search setup.


Is this mean that it can search the word that more equal and more than 3? I noticed in the php code, it has set the limitation character to "3", is it possible to make it 2? It will be easier to let the user search for 2 characters' product code.

But if you think is no possible, then I think 3 characters solution will just fine for now.

Here is my suggestion for couch search function, after you complete with the search code, the couch user can adjust the character length, maybe at "config" file, something like "search_min_length=2". by the way, just a suggestion....

Another problem, how to let it show message, when the character is less than 3 or 4? For now, I am using:
Code: Select all
<cms:no_results>
      <h3>No pages found</h3>
   </cms:no_results>


I want it to display message "The product code is too short".


Hi nsy!

Why you not use html autocomplete search? Or maybe typehead? Just set the min input, lets say 2 chars, when the user input "mi", the search form will give a suggestion with words that contain "mi".

Go find typehead on google
As soon as possible!

Touch me up : abada[dot]zulma[at]gmail[dot]com
@GoingMarryAsap. Thank you for your suggestion, trust me, I considerate to do that earlier. But due to my limit of capabilities, I find it hard to integrate it with couchcms. besides, I have to include a search page for product page, what happen if user need to search the product with 3 characters?

I don't think this autocomplete function can override mysql 4 charcters limit. Forgive me if I misunderstand anything...
nsy wrote: @GoingMarryAsap. Thank you for your suggestion, trust me, I considerate to do that earlier. But due to my limit of capabilities, I find it hard to integrate it with couchcms. besides, I have to include a search page for product page, what happen if user need to search the product with 3 characters?

I don't think this autocomplete function can override mysql 4 charcters limit. Forgive me if I misunderstand anything...


Its easy to integrate mate.

Lets say you use autocomplete, and want to show the kpagelink on <option>.

<cms:pages masterpage='products.php'>
<option><cms:show k_page_title /></option>
</cms:pages>

And all your products will searchable with autocomplete function.

Or you can use the typehead and implement it with json.
As soon as possible!

Touch me up : abada[dot]zulma[at]gmail[dot]com
@nsy

As promised, I've tried to create a solution for 3 character word search taking cue from the article you mentioned - viewtopic.php?p=22189#p22189.

Please copy/paste the following code into your couch/addons/kfunctions.php file (if this file is not present rename kfunctions.example.php to kfunctions.php).
Code: Select all
/////////// begin <cms:search_ex> ///////////
class SearchEx{
    function tag_handler( $params, $node ){
        global $CTX, $FUNCS, $TAGS, $DB, $AUTH;

        extract( $FUNCS->get_named_vars(
                   array(
                         'masterpage'=>'',
                         'keywords'=>'',
                        ),
                   $params) );

        $masterpage = trim( $masterpage );
        if( $keywords ){
            $keywords = trim( $keywords );
        }
        else{
            $keywords = trim( $_GET['s'] );
        }
        // is something being searched?
        if( !$keywords ) return;

        // get the keywords being searched
        $keywords = strip_tags( $keywords );
        $orig_keywords = $keywords;
        $keywords = str_replace( array(",", "+", "-", "(", ")"), ' ', $keywords );

        // http://www.askingbox.com/tip/mysql-combine-full-text-search-with-like-search-for-words-with-3-letters
        $searchwords = array_filter( array_map("trim", explode(' ', $keywords)) );
        $longwords = array();
        $shortwords = array();

        foreach( $searchwords as $word ){
            if( mb_strlen($word, 'UTF-8')>3 ){
                $longwords[] = $word;
            }
            else{
                if( mb_strlen($word, 'UTF-8')==3 ){
                    if(!in_array($val,array('and','the','him','her')))
                    $shortwords[] = $word;
                }
            }
        }

        if( !count($shortwords) ){ // no 3 character words - delegate to original cms:search tag
            if( !count($longwords) ) return;

            $keywords = implode (' ', $longwords );

            // delegate to 'pages' tag
            for( $x=0; $x<count($params); $x++ ){
                $param = &$params[$x];
                if( strtolower($param['lhs'])=='keywords' ){
                    $param['rhs'] = $keywords;
                    $added = 1;
                    break;
                }
            }
            if( !$added ){
                $params[] = array('lhs'=>'keywords', 'op'=>'=', 'rhs'=>$keywords);
            }

            $html = $TAGS->pages( $params, $node, 1 );
        }
        else{
            // we have 3 character words to contend with.

            // craft sql query
            // select ..
            $sql = 'SELECT cp.template_id, cp.id, cf.title, cf.content';

            if( count($longwords) ){
                // add the '+' for boolean search
                $sep = "";
                foreach( $longwords as $kw ){
                    $bool_keywords .= $sep . "+" . $kw;
                    $sep = " ";
                }

                $sql .= ", ((MATCH(cf.content) AGAINST ('".$DB->sanitize($bool_keywords)."') * 1) + (MATCH(cf.title) AGAINST ('".$DB->sanitize($bool_keywords)."') * 1.25)) as score";
            }

            // from ..
            $sql .= "\r\n" . 'FROM ';
            $sql .= K_TBL_FULLTEXT ." cf
            inner join  ".K_TBL_PAGES." cp on cp.id=cf.page_id
            inner join ".K_TBL_TEMPLATES." ct on ct.id=cp.template_id";

            // where ..
            $sql .= "\r\n" . 'WHERE ';
            if( count($longwords) ){
                $sql .= " ((MATCH(cf.content) AGAINST ('".$DB->sanitize($bool_keywords)."' IN BOOLEAN MODE) * 1) + (MATCH(cf.title) AGAINST ('".$DB->sanitize($bool_keywords)."' IN BOOLEAN MODE) * 1.25))";
            }
            else{
                $sql .= '1=1';
            }
            if( $masterpage ){
                // masterpage="NOT blog.php, testimonial.php"
                $sql .= $FUNCS->gen_sql( $masterpage, 'ct.name');
            }
            foreach( $shortwords as $kw ){
                $sql .= " AND (cf.content LIKE '%".$DB->sanitize($kw)."%' OR cf.title LIKE '%".$DB->sanitize($kw)."%')";
            }
            if( $hide_future_entries ){
                $sql .= " AND cp.publish_date < '".$FUNCS->get_current_desktop_time()."'";
            }
            $sql .= " AND NOT cp.publish_date = '0000-00-00 00:00:00'";
            $sql .= " AND cp.access_level<='".$AUTH->user->access_level."'";
            $sql .= " AND ct.executable=1";

            // order
            if( count($longwords) ){
                $sql .= "\r\n";
                $sql .= "ORDER BY score DESC";
            }

            // delegate sql to cms:query
            for( $x=0; $x<count($params); $x++ ){
                $param = &$params[$x];
                if( strtolower($param['lhs'])=='sql' ){
                    $param['rhs'] = $sql;
                    $added = 1;
                    break;
                }
            }
            if( !$added ){
                $params[] = array('lhs'=>'sql', 'op'=>'=', 'rhs'=>$sql);
            }
            $params[] = array('lhs'=>'fetch_pages', 'op'=>'=', 'rhs'=>'1');

            $FUNCS->add_event_listener( 'alter_page_tag_context', array('SearchEx', 'ctx_handler') );
            $node->__my_keywords = array_merge( $longwords, $shortwords );
            $html = $TAGS->pages( $params, $node, 5 );
            $FUNCS->remove_event_listener( 'alter_page_tag_context', array('SearchEx', 'ctx_handler') );
        }

        $CTX->set( 'k_search_query', $orig_keywords, 'global' );
        return $html;

    }// end func tag_handler

    function ctx_handler( $rec, $mode, $params, $node ){
        global $CTX, $FUNCS;

        if( !is_array($node->__my_keywords) ) return;

        $keywords = $node->__my_keywords;
        if( $CTX->get('k_template_is_clonable', true) ){
            $hilited = $FUNCS->hilite_search_terms( $keywords, $rec['title'], 1 );
        }
        else{
            $tpl_title = $CTX->get('k_template_title', true);
            $hilited = $tpl_title ? $tpl_title : $CTX->get('k_template_name', true);
        }
        $CTX->set( 'k_search_title', $hilited );
        $CTX->set( 'k_search_content', $rec['content'] ); //entire content searched

        $hilited = $FUNCS->hilite_search_terms( $keywords, $rec['content'] );
        $CTX->set( 'k_search_excerpt', $hilited ); //hilighted excerpt of searched content
    }
}

$FUNCS->register_tag( 'search_ex', array('SearchEx', 'tag_handler'), 1, 1 );

/////////// end <cms:search_ex> ///////////

With the above code in place, you'll have a new tag named <cms:search_ex>. It is a direct replacement of the core cms:search tag so simply change your existing code to use cms:search_ex instead of cms:search e.g.
Code: Select all
<cms:search_ex keywords='man' masterpage='products.php'>
    <h3><a href="<cms:show k_page_link />"><cms:show k_search_title /></a></h3>
    <cms:show k_search_excerpt />
</cms:search_ex>


Now you should be able to search for three character words too.

Please test this and let me know if it works as expected.

Thanks.
GoingMarryAsap wrote: Or you can use the typehead and implement it with json.


Man, I fell in love with typehead. Have you used it with json?
I have probably thousands of options, i guess json is great for this. Can't find examples of json in downloaded package with docs from github, though. Can you help?
Hi KK,

You are really amazing! I think you are making everything possible.

The code is nicely done, it worked. I can even control the search character length by changing 3 to any number.

I try to combined it with typeahead.js:
Code: Select all
<script>
var substringMatcher = function(strs) {
  return function findMatches(q, cb) {
    var matches, substringRegex;

    // an array that will be populated with substring matches
    matches = [];
   limit: 500,

    // regex used to determine if a string contains the substring `q`
    substrRegex = new RegExp(q, 'i');

    // iterate through the pool of strings and for any string that
    // contains the substring `q`, add it to the `matches` array
    $.each(strs, function(i, str) {
      if (substrRegex.test(str)) {
        matches.push(str);
      }
    });

    cb(matches);
  };
};

/*original code*/
var products = ['products 1', 'products2', 'products 3'];
/*****/

var products = [<cms:pages masterpage="products.php">'<cms:show k_page_title />',</cms:pages>];

$('.typeahead1').typeahead({
  hint: true,
  highlight: true,
  minLength: 1
},
{
  name: 'products',
  source: substringMatcher(products)
});
</script>



This code, it print out all the product's page title:
Code: Select all
var products = [<cms:pages masterpage="products.php">'<cms:show k_page_title />',</cms:pages>];



Do you think this code is written in correct syntax? my Dreamweaver seems to indicate it as a error code. But It does not affect the website, it successfully print out all the product page title as you seem in reference link.

And There is a minor fallback of your search code. Let say I use 3 characters search, the <cms:no_results> does not work for 1 and 2 characters. It won't print out no result message for search terms that less than 3. How can I make it display message like "product code is too short", when user input character that less than 3?
@nsy, congrats!

Regarding your last question.
This can be done with a validator on your input field.

Code: Select all
<cms:input type="text"
                       name="name"
                       label="Search"
                       desc='At least 3 symbols'
                       maxlength="100"
                       required='1'
validator='min_len=3'
validator_msg='required=Please enter something | min_len=Too short!'
/>
13 posts Page 1 of 2

Who is online

In total there are 3 users online :: 0 registered, 0 hidden and 3 guests
(based on users active over the past 5 minutes)

Users browsing this forum: No registered users and 3 guests