Jonas Maurus wrote:
> 
[snip]
> 
> You're welcome. Wait until we have done the other modifications (feedback and
> searching) :-).
> 

Hello Jonas,

Thanks for contributing this localization code to the project.  I see
you have some other stuff in the pipeline as well which is great!

Would you be interested in sharing your ideas for searching in
jyve/turbine?  Unlike localization, I would like to contribute something
here if I can be of help to you, whether a feature spec, a few lines of
code,
or just user-land feedback.

Don't know how far along your team is, but I just had some questions:

1.Did you take Jon *'s suggestion from a while back and think about
using OPaL for this functionality and/or making a more generic search
service as part of Turbine?

2.If it's a jyve specific implementation, are you replacing the
SearchGlobal / SearchResults screens with
something else entirely, or just tweaking what's there?

3.If the latter: conceptually, is parsing a search query string an
action, or part of a screen?  Ie, should you put search string parsing
routines into an action module, pass the query string in as a parameter
from SearchGlobal, then access the parsed string from SearchResults with
a data.user.getTemp("search") kinda thing?

4. How do you localize a search?  Is it reasonable to force non-english
speakers to use and/or/not within a query?

In the interest of shut-up-already-and-post-code, I spent my lunch hour
today and worked up a little something to help me find out what's
already in there and where it could go.  I attached my draft below -
it's a mess and not ready for prime time, so I didn't bother doing a
premature diff (let me know if that would help, though).  The objective
was:

1. Do something minimalist to elicit commentary.
2. Work with the existing code before suggesting we throw it out and
start over.
3. Use my admittedly "script kiddie" level abilties to implement a
simple boolean search.

So I tacked on some code to SearchResults.java to support AND and OR
with multiple search terms. 
I'd like to get back the ability to search on a long multi word string
without having it be "or"'d, however, so I guess parsing for ""'s to
signify a quoted string is next.  Then maybe parse for ![NOT].  Perhaps
same time tommorrow. ;)

Criticism/discussion welcome, or just tell me to go away... ;)

Regards,
~Eric
package org.apache.jyve.screens;

/*
 * Copyright (c) 1997-1999 The Java Apache Project.  All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *
 * 3. All advertising materials mentioning features or use of this
 *    software must display the following acknowledgment:
 *    "This product includes software developed by the Java Apache
 *    Project for use in the Apache JServ servlet engine project
 *    <http://java.apache.org/>."
 *
 * 4. The names "Apache JServ", "Apache JServ Servlet Engine", "Jyve",
 *    "Apache Jyve", "Jyve Project", "Apache Jyve Project" and
 *    "Java Apache Project" must not be used to endorse or promote products
 *    derived from this software without prior written permission.
 *
 * 5. Products derived from this software may not be called "Apache JServ"
 *    nor may "Apache" nor "Apache JServ" appear in their names without
 *    prior written permission of the Java Apache Project.
 *
 * 6. Redistributions of any form whatsoever must retain the following
 *    acknowledgment:
 *    "This product includes software developed by the Java Apache
 *    Project for use in the Apache JServ servlet engine project
 *    <http://java.apache.org/>."
 *
 * THIS SOFTWARE IS PROVIDED BY THE JAVA APACHE PROJECT "AS IS" AND ANY
 * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE JAVA APACHE PROJECT OR
 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
 * OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * This software consists of voluntary contributions made by many
 * individuals on behalf of the Java Apache Group. For more information
 * on the Java Apache Project and the Apache JServ Servlet Engine project,
 * please see <http://java.apache.org/>.
 *
 */

// JDK Stuff
import java.io.*;
import java.sql.*;
import java.util.*;

// Servlet Stuff
import javax.servlet.*;
import javax.servlet.http.*;

// External Stuff
import org.apache.turbine.modules.*;
import org.apache.turbine.util.*;
import org.apache.turbine.util.access.*;
import org.apache.turbine.util.db.*;
import com.workingdogs.village.*;
import org.apache.ecs.*;
import org.apache.ecs.html.*;

// Own Stuff
import org.apache.jyve.localization.*;

public class SearchResults extends Screen
{
    public ConcreteElement build( RunData data ) throws Exception
    {
        
data.setTitle(TurbineServices.getInstance().getService(TurbineServices.LOCALIZATION).getString("SEARCHRESULTS_TITLE"));
        
        ElementContainer ec = new ElementContainer();
        ec.addElement ( ScreenLoader.getInstance().eval ( data, "SearchGlobal" ) );
        ec.addElement ( new HR().setSize(1).setNoShade(true));
        
       ec.addElement (new 
B(TurbineServices.getInstance().getService(TurbineServices.LOCALIZATION).getString("SEARCHRESULTS_SEARCHRESULTMSG"))
 );
        ec.addElement ( new P() );
        
        String search = data.parameters.getString("search", null );
        if ( search == null || search.length() == 0 )
        {
          data.setMessage 
(TurbineServices.getInstance().getService(TurbineServices.LOCALIZATION).getString("SEARCHRESULTS_NOVALIDSEARCH"));
            data.setScreen ("SearchGlobal");
        }
        
        // get a connection to the db
        DBConnection db = DBBroker.getInstance().getConnection();
        Connection connection = db.getConnection();
        
        StringBuffer sql = new StringBuffer();
        sql.append ( "select distinct" );
        sql.append ( " p.project_id, p.project_value " );
        sql.append ( ", f.faq_id, f.faq_value " );
        sql.append ( ", t.topic_id, t.topic_value " );
        sql.append ( ", q.question_id, q.question_value " );
        sql.append ( ", a.answer_id, a.answer_value " );
        sql.append ( ", p.deleted, f.deleted " );
        sql.append ( ", t.deleted, q.deleted " );
        sql.append ( ", a.deleted " );

        sql.append ( " from " );
        sql.append ( " project p, faq f, topic t, question q, answer a " );

        sql.append ( " where " );
        sql.append ( " p.project_id=f.project_id " );
        sql.append ( " and " );
        sql.append ( " f.faq_id=t.faq_id " );
        sql.append ( " and " );
        sql.append ( " t.topic_id=q.topic_id " );
        sql.append ( " and " );
        sql.append ( " q.question_id=a.question_id " );

        sql.append ( " and " );
        sql.append ( " p.deleted='N' " );
        sql.append ( " and " );
        sql.append ( " f.deleted='N' " );
        sql.append ( " and " );
        sql.append ( " t.deleted='N' " );
        sql.append ( " and " );
        sql.append ( " q.deleted='N' " );
        sql.append ( " and " );
        sql.append ( " a.deleted='N' " );
        
        sql.append(buildSearchCriteria(search,"or"));
        
        /*
        sql.append ( " and " );
        sql.append ( " (p.project_value LIKE '%" );
        sql.append ( search );
        sql.append ( "%' " );
        sql.append ( " OR " );
        sql.append ( " t.topic_value LIKE '%" );
        sql.append ( search );
        sql.append ( "%' " );
        sql.append ( " OR " );
        sql.append ( " f.faq_value LIKE '%" );
        sql.append ( search );
        sql.append ( "%' " );
        sql.append ( " OR " );
        sql.append ( " q.question_value LIKE '%" );
        sql.append ( search );
        sql.append ( "%' " );
        sql.append ( " OR " );
        sql.append ( " a.answer_value LIKE '%" );
        sql.append ( search );
        sql.append ( "%')" );
        */
        
        // execute the query
        QueryDataSet qds = new QueryDataSet( connection, sql.toString());
        int size = 0;
        try
        {
            qds.fetchRecords();
            size = qds.size();
            if ( size > 0 )
            {
                Table table = new Table().setBorder(0).setCellPadding(5);
                TR top = new TR().setBgColor("006666");
                top.addElement ( new TD().addElement ( 
                new 
Font().addElement(TurbineServices.getInstance().getService(TurbineServices.LOCALIZATION).getString("SEARCHRESULTS_PROJECTMSG")).setColor(HtmlColor.white).setSize(4)
 )
                         );
                top.addElement ( new TD().addElement ( 
                new 
Font().addElement(TurbineServices.getInstance().getService(TurbineServices.LOCALIZATION).getString("SEARCHRESULTS_FAQMSG")).setColor(HtmlColor.white).setSize(4)
 )
                         );
                top.addElement ( new TD().addElement ( 
                new 
Font().addElement(TurbineServices.getInstance().getService(TurbineServices.LOCALIZATION).getString("SEARCHRESULTS_TOPICMSG")).setColor(HtmlColor.white).setSize(4)
 )
                         );
                top.addElement ( new TD().addElement ( 
                new 
Font().addElement(TurbineServices.getInstance().getService(TurbineServices.LOCALIZATION).getString("SEARCHRESULTS_QUESTIONMSG")).setColor(HtmlColor.white).setSize(4)
 )
                    );
                table.addElement ( top );
                for ( int i=0;i<size;i++ )
                {
                    String project_value = 
qds.getRecord(i).getValue("project_value").asString();
                    String faq_value = 
qds.getRecord(i).getValue("faq_value").asString();
                    String topic_value = 
qds.getRecord(i).getValue("topic_value").asString();
                    String question_value = 
qds.getRecord(i).getValue("question_value").asString();
                    int project_id = qds.getRecord(i).getValue("project_id").asInt();
                    int faq_id = qds.getRecord(i).getValue("faq_id").asInt();
                    int topic_id = qds.getRecord(i).getValue("topic_id").asInt();
                    int question_id = qds.getRecord(i).getValue("question_id").asInt();
                    
                    DynamicURI pduri = new DynamicURI(data, "DisplayProjects", 
"SetAll")
                        .addPathInfo("project_id", project_id );
                    DynamicURI fduri = new DynamicURI(data, "DisplayFaqs", "SetAll")
                        .addPathInfo("project_id", project_id )
                        .addPathInfo("faq_id", faq_id );
                    DynamicURI tduri = new DynamicURI(data, "DisplayTopics", "SetAll")
                        .addPathInfo("project_id", project_id )
                        .addPathInfo("faq_id", faq_id )
                        .addPathInfo("topic_id", topic_id );
                    DynamicURI qduri = new DynamicURI(data, "DisplayQuestionAnswer", 
"SetAll")
                        .addPathInfo("project_id", project_id )
                        .addPathInfo("faq_id", faq_id )
                        .addPathInfo("topic_id", topic_id )
                        .addPathInfo("question_id", question_id );

                    TR tr = new TR().setBgColor("CCCCCC");
                    tr.addElement ( 
                        new TD().addElement ( new A()
                            .addElement(project_value).setHref ( pduri.toString() ) ) 
);
                    tr.addElement ( 
                        new TD().addElement ( new A()
                            .addElement(faq_value).setHref ( fduri.toString() ) ) );
                    tr.addElement ( 
                        new TD().addElement ( new A()
                            .addElement(topic_value).setHref ( tduri.toString() ) ) );
                    tr.addElement ( 
                        new TD().addElement ( new A()
                            .addElement(question_value).setHref ( qduri.toString() ) ) 
);
                    table.addElement ( tr );
                }
                ec.addElement ( table );
            }
            else
            {
             data.setMessage 
(TurbineServices.getInstance().getService(TurbineServices.LOCALIZATION).getString("SEARCHRESULTS_NOMATCHMSG"));
                return ScreenLoader.getInstance().eval ( data, "SearchGlobal" );
            }
        }
        finally
        {
            if ( qds != null ) qds.close();
            DBBroker.getInstance().releaseConnection(db);
        }
        ec.addElement ( new P());
       ec.addElement ( 
TurbineServices.getInstance().getService(TurbineServices.LOCALIZATION).getString("SEARCHRESULTS_TOTALMSG")
 + size );
        ec.addElement ( new P());
        
        return ec;
    }
  private String buildSearchCriteria(String search, String conj)
    {
    StringTokenizer searchTokenizer = new StringTokenizer(search);
    StringBuffer searchBuffer = new StringBuffer();

    if (searchTokenizer.countTokens() > 1)
        {
        boolean conjunction = true;
        
        while (searchTokenizer.hasMoreTokens())
            {
            String searchToken = searchTokenizer.nextToken();
            if (searchTokenizer.hasMoreTokens())
                {
                if (conjunction)
                    {
                    searchBuffer.append(" '%"+searchToken+"%' ");
                    conjunction = false;
                    }
                else
                    {
                    if (searchToken.equalsIgnoreCase("and") || 
searchToken.equalsIgnoreCase("or"))
                        {
                        searchBuffer.append( " "+searchToken.toUpperCase()+" ");
                        conjunction = true;
                        }
                    else 
                        {
                        searchBuffer.append(" " + conj.toUpperCase() + " 
'%"+searchToken+"%' ");
                        }
                    }
                }
            else
                {
                if (!conjunction) searchBuffer.append(" " + conj.toUpperCase());
                searchBuffer.append(" '%"+searchToken+"%' ");   
                }
            }
        }
    else searchBuffer.append(" '%" + search + "%' ");
    
    StringBuffer sqlBuffer = new StringBuffer();
    String[] dbFields = {"p.project_value",
                 "t.topic_value",
                 "f.faq_value",
                 "q.question_value",
                 "a.answer_value"};

    sqlBuffer.append ( " AND ( ");
    
    for (int i=0; i < dbFields.length; i++)
        {
        sqlBuffer.append ( " ( " );
        StringTokenizer tokenizer = new StringTokenizer(searchBuffer.toString());
        while (tokenizer.hasMoreTokens())
            {
            String token = tokenizer.nextToken();
            if (!(token.equalsIgnoreCase("and") || token.equalsIgnoreCase("or")))
                sqlBuffer.append ( dbFields[i]+" LIKE " );
            sqlBuffer.append ( token + " ");
            }
        if (i < dbFields.length - 1) sqlBuffer.append ( " ) OR " );
        }
    
    sqlBuffer.append ( " ) ) " );
    return sqlBuffer.toString();
    }
}




Reply via email to