SearchOrder=4, our solution

Hi,

We also needed a solution for the SearchOrder=4 bug. In our case we needed the full text search to search through views with up to 1000 docs (jobs in this case). These jobs needed to be in order of the view. Our searchable views are all set as ‘Treat view contents as html’.

In short our solution works as follows:

  1. in the $$SearchTemplate form for the view, rename the field ‘$$ViewBody’ to ‘$$ViewBodyForAgent’

  2. create a Java agent to do the search for you and have it store the results in the ‘$$ViewBodyForAgent’ field of the context doc

  3. place the Java agent in the WebQueryOpen of the ‘$$SearchTemplate for x’ form

Below is the Java agent we used. It gets all entries from a view (which are in view order) and than searches the same view. It loops through all entries, only returning those found in the search result and between the requested ‘Start’ and ‘Start + Count’. It also sets the various fields needed on the html search result form like ‘Hits’ etc. It works with paged search results as well because of this.

I simply copied and pasted the source into here for you guys, so there might some specific things in here needed for our implementation which you don’t need.

A couple of things/pointers:

  • there is no need to change the URL to search a view, since it uses the template anyway

  • this solution works with the standard fields on a search template

  • the source below works for html views (which we use), you’ll have to add column formatting if you want it to work on non html views

  • the performace drawback comes from the agent always having to loop all documents to return the search result in the view order. In our case not a real problem because of the number of docs per view (< 1000)

  • we always search views using the view order, but you can improve on this solution by only calling this agent if SearchOrder=4, hiding the $$ViewBodyForAgent field and showing the standard $$ViewBody field

    public void NotesMain() {

      try {
    
      	Session session = getSession();
    
      	AgentContext agentContext = session.getAgentContext();
    
      	Database db = agentContext.getCurrentDatabase();
    
    
    
      	// Get the argument (1 argument)
    
      	lotus.domino.Document docContext = agentContext.getDocumentContext();
    
    
    
      	String sServer_Name = docContext.getItemValueString("Server_Name");
    
      	
    
      	String sQueryStringDecoded = docContext.getItemValueString("Query_String_Decoded");
    
      	System.out.println(sQueryStringDecoded);
    
    
    
      	// Extract query string
    
      	String sQuery = "";
    
      	String sQueryStart = "";
    
      	String sQueryCount = "10";
    
      	String sQueryHits = "";
    
      	String sQuerySearchMax = "";
    
      	StringTokenizer stQuery = new StringTokenizer(sQueryStringDecoded, "&");
    
      	String sCompanyBranch = "";
    
      	String sSelect = "";
    
      	while (stQuery.hasMoreTokens()) {
    
      		String sNameValuePair = stQuery.nextToken();
    
      		String sName = "";
    
      		String sValue = "";
    
      		// Treat 'Query' argument differently, it mcan contain an '=' as well
    
      		if (sNameValuePair.toLowerCase().indexOf("query=") == 0) {
    
      			// Check which name/value pair we have here
    
      			sQuery = sNameValuePair.substring(6);
    
      		}
    
      		else {
    
      			StringTokenizer stNameValuePair = new StringTokenizer(sNameValuePair, "=");
    
      			if (stNameValuePair.hasMoreTokens())
    
      				sName = stNameValuePair.nextToken();
    
      			if (stNameValuePair.hasMoreTokens())
    
      				sValue = stNameValuePair.nextToken();
    
      			// Check which name/value pair we have here
    
      			if (sName.toLowerCase().equals("start"))
    
      				sQueryStart = sValue;
    
      			// Check which name/value pair we have here
    
      			if (sName.toLowerCase().equals("count"))
    
      				sQueryCount = sValue;
    
      			// Check which name/value pair we have here
    
      			if (sName.toLowerCase().equals("searchmax"))
    
      				sQuerySearchMax = sValue;
    
      		}
    
      	}
    
    
    
      	int iQueryStart = 1;
    
      	try {
    
      		iQueryStart = Integer.parseInt(sQueryStart);
    
      	} catch (Exception e) {
    
      		iQueryStart = 1;
    
      	}
    
    
    
      	int iQueryCount = 10;
    
      	String sViewName = docContext.getItemValueString("ViewName");
    
      	if (sViewName.equals("Search Vacancies2 (Web)")) {
    
      		iQueryCount = 3;
    
      	}
    
      	else {
    
      		try {
    
      			iQueryCount = Integer.parseInt(sQueryCount);
    
      		} catch (Exception e) {
    
      			iQueryCount = 10;
    
      		}
    
      	}
    
    
    
      	// Default to 250, if we use less, we get the wronng results because search results are not 
    
      	// ordered according to the view
    
      	int iQuerySearchMax = 250;
    

// try {

// iQuerySearchMax = Integer.parseInt(sQuerySearchMax);

// } catch (Exception e) {

// iQuerySearchMax = 250;

// }

		// Get view

		View vw = db.getView(sViewName);

		System.out.println("ViewName=" + sViewName);

		

		// Get all entries from view

		vw.clear();

		vw.refresh();

		ViewNavigator nav = vw.createViewNav();



		// Search view to get documents to return

		System.out.println("sQuery=" + sQuery);

		vw.FTSearch(sQuery, iQuerySearchMax);

		ViewEntryCollection vecFiltered = vw.getAllEntries();

		int iTotalHits = vecFiltered.getCount();



		// Column settings

		Vector columns = vw.getColumns();



		// Loop through all entries, returning only those found in filtered view. This way 

		// we retain the view order of the view.

		String sViewBody = "";

		int iCurrent = 1;

		int iHits = 0;

		ViewEntry entry = nav.getFirst();

		while ((entry != null) && (iCurrent <= (iQueryStart + iQueryCount))) {

			// Before we do anything, get a ref. to the next one (in case we remove the current one)

			ViewEntry nextEntry = nav.getNext();

			

			ViewEntry filteredEntry = null;

			try {

				filteredEntry = vecFiltered.getEntry(entry);

			} catch (Exception e) {

				e.printStackTrace();

			}

			if (filteredEntry != null) {

				if ((iCurrent >= iQueryStart) && (iCurrent < (iQueryStart + iQueryCount))) {

					// Return only entries found by FTSearch

					Vector vColumnValues = entry.getColumnValues();



					for (int j=0; j<vColumnValues.size(); j++) {

						// Not a hidden column?

						if (!((ViewColumn)columns.elementAt(j)).isHidden()) {

							sViewBody += vColumnValues.elementAt(j);

						}

					}

					sViewBody += "\n";

					iHits++;

				}

				iCurrent++;

			}

			

			// Next

			entry = nextEntry;

		}



		// Set value of '$$ViewBodyForAgent' with our column values

		docContext.replaceItemValue("$$ViewBodyForAgent", sViewBody);



		// Return the query

		docContext.replaceItemValue("Query", sQueryStringDecoded);



		// Return the start number

		docContext.replaceItemValue("Start", new Integer(iQueryStart));



		// Return the number of hits

		docContext.replaceItemValue("Hits", new Integer(iHits));



		// Return the total number of hits

		docContext.replaceItemValue("TotalHits", new Integer(iTotalHits));

		

	} catch(Exception e) {

		e.printStackTrace();

	}

}