Sun Java System Portal Server 7.1 Developer's Guide

Working Through An Example Search Application

This section discusses the SearchDemo example application provided with the Java search SDK. The purpose of this example is to show how to use a Search object to submit a query to the search server and how to extract the results from the Search object. The example application is very simple, and limits use of Java to achieving the goals of the example. It creates a Java applet that presents the user with a text field in which to enter a search query, and a Search button to initiate the search. The results of the query are read from a SearchInputStream returned by the Search object. The query results are displayed to standard output as plain text.

Import the Necessary Classes

In your favorite editor or Java development environment, view the search SDK file SearchDemo.java. This demo runs as a stand alone application or as an applet. The search package is provided as part of the Search Server Java SDK, while java.applet, java.awt, and java.io are standard Java packages.

package com.sun.portal.search.demo;
import com.sun.portal.search.search.*;
import java.applet.Applet;
import java.awt.*;
import java.io.*;

Define the SearchDemo Class

The class SearchDemo is an applet, so it extends the class Applet. SearchDemo defines init() and main() methods which allow it to run as an applet or as a stand alone (command line) program.


Example 29–1 SearchDemo


/**
* Applet/application for simple query interface. Can be used as an
* example for those who want to create their own java interface.
* This example demonstrates search only.  Browse, determining
* the schema of the search server and obtaining the taxonomy
* of the search server will be demonstrated in other examples.
*/

public class SearchDemo extends Applet {
    /** Run as an applet. */
    public void init() {
        String rdm = getParameter("RDMServer");
        SimpleSearch ss = new SimpleSearch(rdm);
        SearchPanel sp = new SearchPanel(ss);
        setLayout(new FlowLayout(FlowLayout.CENTER));
        add(sp);
    }
    /** Run as an application. */
    public static void main(String argv[]) throws Exception {
        int args = argv.length;
        String SearchOutputFile = null;
        if (args != 1 && args != 2 && args != 3) {
            System.out.println("args: RDMServer [query]
            [search_output_file_name]");
            return;
        }
        String rdm = argv[0];  // rdm search server, eg,
        // http://portal.siroe.com:2222/ps/search
        SimpleSearch ss = new SimpleSearch(rdm);
        if (args == 3) {
            --args;
            ss.setSearchfile(argv[2]); // dump raw Search results to this file
        }
        if (args == 1) {
            // run from a search box
            Frame f = new Frame();
            SearchPanel sp = new SearchPanel(ss);
            f.add(sp);
            f.pack();
            f.show();
        }
        else {
            // run from command line
            String query = argv[1];
            ss.doSearch(query);
        }
    }
}

There is a helper class called SearchPanel which handle the applet GUI. It sets up a search panel with a text box to enter a query and a submit button to run the query. See the source file for more details.

Define the SimpleSearch Class

Notice the private helper class SimpleSearch. This is where the search is set up and executed and we will look at it in more detail here. The applet/command line class SearchDemo sets up the arguments for SimpleSearch using either applet or command line parameters. It then calls the SimpleSearch.doSearch(String scope) method to execute the search and display the results. The SimpleSearch constructor takes the location of the search server as an argument. In this way, a single SimpleSearch object can be used repeatedly to run searches against the remote search server.

The SimpleSearch.setSearchfile(String filename) method is used by the main program to direct search results to a file when running in command line mode.


Example 29–2 SimpleSearch Class


/** Performs a simple search and displays its results. */
class SimpleSearch {
    String RDMServer;
    String SearchOutputFile;
    /**
    * SimpleSearch constructor
    * @param rdm - the rdm search server, 
		eg, http://portal.siroe.com:2222/portal/search
    */
    public SimpleSearch(String rdm) {
        System.out.println("Sun Java System Search Java Demo");
        RDMServer = rdm;
    }
    /**
    * @param filename - a file to dump raw Search results into - only
    * use if running from the comand line or an applet with file
    * system access
    */
    public void setSearchfile(String filename) {
        SearchOutputFile = filename;
    }
    /** Execute a search */
    public void doSearch(String scope) throws IOException {
        ...see

Define the SimpleSearch Class


...
    }
}

Before submitting the search, SimpleSearch needs to create a Search object. The constructor for the Search class takes several arguments as discussed previously.


Example 29–3 doSearch Class


/** Execute a search */
public void doSearch(String scope) throws IOException {
    /* The Search class encapsulates the search.
    ** It’s parameters are:
    **  1) the search string
    **  2) the attributes you want returned, comma delimited
    **  3) sort order, comma delimited, - descending, + ascending
    **  4) first hit
    **  5) number of hits
    **  6) query language, eg search, taxonomy-basic, schema-basic, etc
    **  7) database to search
    **  8) The RDM server URL, eg, http://portal.siroe.com:2222/ps/search
    **  9) Access token (null for anonymous access, or valid iPlanet 
				Directory Server Access Management Edition session id)
    */
    Search  search = new Search(
        scope,
        "score,url,title,description",
        "-score",
        1,
        20,
        "search",
        null,
        RDMServer,
        null
    );

The Search constructor arguments used here are:

scope

The search scope is the actual query run by the search server. It is the scope argument to doSearch() and ultimately derives from either the applet input panel or a command line argument to the main program.

viewAttributes = "score,url,title,description"

The requested attribute set shown here will result in the server returning the score, url, title, and description of all documents that match the query.

viewOrder = "-score"

A comma delimited list of the attributes to be used to sort the results. A minus sign indicates descending order, a plus sign indicates ascending order. In this case, sort the results by decreasing numerical score value, and use alphabetical order of the title as the secondary sort order.

firstHit = 1

The hit number of the first returned result.

viewHits = 20

The maximum number of results to return.

queryLanguage = "search"

The search server query language. Use search for normal searches.

RDMServer

The URL of the remote search engine, specified as an argument to the SimpleSearch constructor.

ssoToken = null

The Access Manager software single sign on token. Not used in this case, implying anonymous search.

Execute the Search Query

An output stream is created to hold the search results and paginate through the search results for a fixed number of pages, in this case five pages in total, where each page has viewHits (=20) results. The first page starts with the first hit (firstHit=1). The search is executed again for each page of results. It is possible to cache the results for all pages with a single search of course, but it is often easier to simply resubmit the search each time. This is equivalent to a user clicking a next button in a search user interface.


/* Execute the query. */
System.out.println("\\nSearch results for ’" + scope + "’");
 DataOutputStream sos = null;
if (SearchOutputFile != null) {
try {
sos = new DataOutputStream(new FileOutputStream(SearchOutputFile));
}
catch (Exception e1) {
System.out.println("Error: failed to create output file: " + e1);
}
}
int  pagenum = 1;
int  pagesize = 10;
SearchBuffer firstPageSearch = new SearchBuffer();
for (; pagenum <= 5; pagenum++) {
int firstHit = (pagenum-1)*pagesize+1;
try {
search.doQuery(firstHit, pagesize);
}
catch (Exception ex) {
ex.printStackTrace();
break;
}
// Check the result count. -1 indicates an error.
if (search.getResultCount() <= 0)
break;

The results are stored in the Search object. Now do something with the results. The functions doSomethingWithResults() and displayHTMLResults() will be defined in this file. They each show a different way of extracting the results from the Search object.

Display the Results

The example application displays the query results to standard output or to a named file. In reality, you would do more with the results than just print them like this, but once you know how to get the results out of the Search object, it is up to you what you do with them. You can use standard Java functionality to process the results in any way you like.

The Search object has a method called getResultStream() that returns a SearchInputStream object. Each result is read from this Search stream in turn. Note that the client server connection uses an efficient streamed protocol; it is conceivable that the server is still returning later results while the client is processing the first results. For each Search object read from the result stream you can use the getValue() method to get the value of a particular field, for example, getValue("title") gets the title of a Search object.

First, print out some general result information:


System.out.println("=========================================");
System.out.println("page " + pagenum
+ ": hits " + search.getFirstHit()
+ " to " + (search.getFirstHit() + search.getResultCount() - 1)
+ " out of " + search.getHitCount()
+ " across " + search.getDocumentCount() + " documents");
System.out.println("=========================================");
System.out.println();

Now, retrieve each search hit from the result stream as Search objects and print its URL, title, description, and score to the output stream (either the Java console, standard output, or a named output file).


SearchInputStream resultStream = search.getResultStream();
Search search;
/* Examine the results of the search. The following
* code loops through the stream of Search instances. */
for (search = resultStream.readSearch(); search != null; 
search = resultStream.readSearch()) {
    // For illustration, dump out the entire Search on 
			the first page only.
    if (pagenum == 1)
        firstPageSearch.write(search.toByteArray());
        /* Now we use the getValue() method to get
        * the values of each of the requested
        * attributes. URL is special and has
        * its own accessor method.
        */
        String  u = search.getURL();
        String  t   = search.getValue("title");
        String  d   = search.getValue("description");
        String  sc  = search.getValue("score");

        /* do something with the results */
        System.out.println(
            "TITLE:       " + t  + "\\n" +
            "URL:         " + u  + "\\n" +
            "SCORE:       " + sc + "\\n" +
            "DESCRIPTION: " + d  + "\\n" +
            "--------------------------------------------\\n"
        );
        // If there is a Search output file, write the Search 
				data there too...
        if (sos != null) {
            try {
                sos.writeBytes(search.toString());
            }
            catch (Exception e1) {
                System.out.println("Error: failed to write to Search
                output file: " + e1);
            }
        }
    }
    // Break if the largest requested hit has been displayed
    if (search.getHitCount() <= (firstHit + pagesize - 1))
        break;
    }
    if (firstPageSearch == null)
        System.out.println("No matching documents found.");
    }