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:
-
in the $$SearchTemplate form for the view, rename the field ‘$$ViewBody’ to ‘$$ViewBodyForAgent’
-
create a Java agent to do the search for you and have it store the results in the ‘$$ViewBodyForAgent’ field of the context doc
-
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();
}
}