Add Custom Search Criteria
In the geoportal, it is possible to filter search results based on certain metadata elements. For example, you can retrieve documents with specific terms in the title by prefixing the search query in the Search field with title:searchTerm. This is enabled by the Lucene index, which classifies information in a metadata element with a heading by which a user would search. Search syntax is further discussed in Using Lucene Search Text Queries.
It is also possible to add this customized element search as a search filter in the list of available search options shown in the Additional Options dialog on the Search page. This topic will first describe how to designate a specific element for search, and then how to add this search to the Additional Options dialog as a custom search filter.
注意:
When you add the customized search criteria, you can also search the custom field using lucene syntax in the CS-W interface. However, adding the custom field does not alter the geoportal's GetCapabilities operation; the only properties explicitly listed in the geoportal's GetCapabilities are the spatial predicates (e.g., BBOX, Intersects, Within).
Steps for how to add a custom search criteria are discussed in this topic.
Designate a Specific Element for Search and Verify that it is Indexed
This section assumes that you have an initial understanding of the geoportal's property-meanings.xml file as described in Details of Lucene Indexing in the Geoportal. In this example, you will configure the geoportal to index an element from the INSPIRE metadata schema, as defined by the inspire-iso-19115-definition.xml file.
Tip: This customization does not require the Geoportal Server source code; however, you will be creating a new java class in this customization, so java programming knowledge is recommended. If you use an integrated development environment (IDE, such as Eclipse) to compile the new class, remember to import the geoportal.war file into your project as you develop.
Identify the element you want to be searchable from Additional Options
Likely you already have in mind a metadata element that your organization would like to be searchable from the Additional Options interface. It is important to be able to locate this element in one or more metadata profiles your geoportal supports. Verify that you can find the metadata element, either by locating it in the definition.xml files (found in the \\geoportal\WEB-INF\classes\gpt\metadata subfolders) or from a profile in the geoportal's metadata editor interface. In this example, we will add a search filter for the Lineage field of an ISO metadata document to theAdditional Options search interface. To see the Lineage field in the geoportal metadata editor, launch the geoportal and log in as a publisher user or administrator. Then, click the Administration tab, and then the Add link. Select the Use dedicated editor to create metadata manually option, and then choose the INSPIRE (Data) profile. Scroll through the form, and find the section titled Quality&Validity. In this section, you will see the Lineage metadata element.
Determine if the chosen element is already indexed by default
If the element that you want to search from the Additional Options interface appears in one of the geoportal's default metadata editors, it is likely that this element is already indexed by default. However, if you have created a custom metadata profile with new metadata parameters, or added new metadata elements to the default editors, then you may need to define the indexing for the element. Follow guidance in the "Determine if the chosen element is already indexed by default" section in the Details of Lucene Indexing in the Geoportal topic. After reading that section and carrying out recommendations for how the chosen element is indexed, you should be able to input a lucene query for your element in the search field on the geoportal Search page and retrieve relevant results.
Add the New Search Element to the Additional Options Dialog
In this task, you will prepare your search element for search and display in the Additional Options dialog. Note that in this example, our new searchable element, lineage, is a text field. If your new element is a date field or a multiselect field, the steps below should be adapted to the type of the field.
Build a new class for the new search filter
The geoportal compiled code already includes classes for the default search options seen in the Additional Options dialog. To include your additional filter in the dialog, you will need to create a new class that provides information to the geoportal about your element. The new class must implement the ISearchFilter interface, or extend/implement one of the children of ISearchFilter. You can use any name for your new class, but if you want to follow the naming convention of the other search filter classes within the geoportal, the name of your class would beSearchFilter<name_of_your_indexing_field>.java. The code shown below is an example of a class that could be used for adding our example lineage element. After you author and compile the new class, put the resulting class file into the \\geoportal\WEB-INF\classes\gpt\search\directory.package gpt.search;
import com.esri.gpt.catalog.search.ISearchFilter;
import com.esri.gpt.catalog.search.SearchException;
import com.esri.gpt.catalog.search.SearchParameterMap;
import com.esri.gpt.catalog.search.SearchParameterMap.Value;
import com.esri.gpt.framework.util.Val;
@SuppressWarnings("serial")
public class SearchFilterLineage implements ISearchFilter {
// key to be used to serialize class to a map
private static String KEY_LINEAGE = "lineage";
// instance variable
private String lineage;
// property (Can be used by jsf(advanced search page)
public String getLineage() {
return Val.chkStr(lineage);
}
// property (Can be used by jsf(advanced search page)
public void setLineage(String lineage) {
this.lineage = lineage;
}
// Serialize class instance into a map
public SearchParameterMap getParams() {
SearchParameterMap map = new SearchParameterMap();
map.put(KEY_LINEAGE, map.new Value(this.getLineage(), ""));
return map;
}
// The class may receive a new map for deserialization (e.g. saved searches
// can trigger this
public void setParams(SearchParameterMap parameterMap) throws SearchException {
Value val = parameterMap.get(KEY_LINEAGE);
this.setLineage(val.getParamValue());
}
// Deep comparison of filters
public boolean isEquals(Object obj) {
if (obj instanceof SearchFilterLineage) {
return ((SearchFilterLineage) obj).getLineage().equals(this.getLineage());
}
return false;
}
// This will be called by the clear button
public void reset() {
this.setLineage("");
}
// Before search, validate will be called. An exception can be thrown
// that will stop the search and the error is displayed on the search page
public void validate() throws SearchException {
if (this.getLineage().equals("this should throw an exception")) {
throw new SearchException("this should throw an exception");
}
}
}
Store instances of your new class in the geoportal session variables
Search parameters and their values are stored in session variables. These variables are created when a user loads the first web page of the site, and the variables then persist till the user closes the browser or does not create any web requests for a certain amount of time. The JavaServer Faces framework, upon which the Geoportal Server is built, has a configuration file where session variables are stored. This file is located in the \\geoportal\WEB-INF directory, and is called gpt-faces-config.xml. You will need to update this file in two places.
- Under the section titled <!- - Search Beans - ->, add the following new managed bean to store your new variables in the session. Note that in the example below, we reference our example Lineage element; you will need to edit this to match the element for which you are customizing the search:
<!--managed bean for lineage search--> <managed-bean> <description>Search Filter with lineage properties</description> <managed-bean-name>SearchFilterLineage</managed-bean-name> <managed-bean-class>gpt.search.SearchFilterLineage</managed-bean-class> <managed-bean-scope>session</managed-bean-scope> </managed-bean>
- In the managedProperty called miscelleniousFilters, you will need to make some edits. Verify that the value-class is set tocom.esri.gpt.catalog.search.ISearchFilter. In the list of values, add a value that references your new managed bean. In the example below, we add the line <value>#{SearchFilterLineage}</value>:
<managed-property> <property-name>miscelleniousFilters</property-name> <property-class> com.esri.gpt.catalog.search.SearchFiltersList </property-class> <list-entries> <value-class> com.esri.gpt.catalog.search.ISearchFilter </value-class> <value>#{SearchFilterHarvestSites}</value> <value>#{SearchFilterLineage}</value> </list-entries> </managed-property>
Override the Query Servlet Class
For your custom search to work from the search page, it must also work from the REST URL. The RestQueryServlet class is the controller for REST searches and should be overridden. The code below is shown for creating the class that will override the RestQueryServlet class. Open up a text editor and copy the lines below into it. Save the file as CustomRestQueryServlet.java, in the \\geoportal\WEB-INF\classes\gpt\searchfolder.
注意:
In this example, you see that lineage is the name of the rest queryable. You will need to update this for the element you want to search.
package gpt.search;
import javax.servlet.http.HttpServletRequest;
import com.esri.gpt.catalog.discovery.rest.RestQuery;
import com.esri.gpt.catalog.discovery.rest.RestQueryParser;
import com.esri.gpt.catalog.search.SearchCriteria;
import com.esri.gpt.control.georss.RestQueryServlet;
import com.esri.gpt.framework.context.RequestContext;
import com.esri.gpt.framework.util.Val;
public class CustomRestQueryServlet extends RestQueryServlet {
private static String REST_PARAM_KEY = "lineage";
//Relate the rest queryable to the CSW queryables
protected RestQuery parseRequest(HttpServletRequest request, RequestContext context) {
RestQuery query = super.parseRequest(request, context);
RestQueryParser parser = new RestQueryParser(request,context,query);
// "lineage" will be the name of the rest queryable
parser.parsePropertyIsLike(REST_PARAM_KEY, "dc:lineage");
/** The below is shown as an example
parser.parseRepositoryId("rid");
parser.parseResponseFormat("f");
parser.parseResponseGeometry("geometryType");
parser.parseResponseStyle("style");
parser.parseResponseTarget("target");
parser.parseStartRecord("start",1);
parser.parseMaxRecords("max",10);
parser.parsePropertyIsEqualTo("uuid","uuid");
parser.parsePropertyIsLike("searchText","anytext");
parser.parsePropertyList("contentType","dc:type",",",true);
parser.parsePropertyList("dataCategory","dc:subject",",",true);
parser.parsePropertyRange("after","before","dct:modified");
parser.parseSpatialClause("bbox","spatialRel","geometry");
parser.parseSortables("orderBy");
**/
return query;
}
//Populate the searchCriteria with the rest queryable
protected SearchCriteria toSearchCriteria(HttpServletRequest request,
RequestContext context, RestQuery query) {
SearchCriteria criteria = super.toSearchCriteria(request, context, query);
RestQueryParser parser = new RestQueryParser(request,context, query);
String sLineage = Val.chkStr(parser.getRequestParameter(REST_PARAM_KEY));
if (sLineage.length() > 0) {
SearchFilterLineage filterLineage = new SearchFilterLineage();
filterLineage.setLineage(sLineage);
criteria.getMiscelleniousFilters().add(filterLineage);
}
return criteria;
}
}
Update geoportal's web.xml to point to your new queryServlet Class
Navigate to your \\geoportal\WEB-INF folder and open the web.xml file in a text editor. Find the <servlet> reference with the <servlet-name> set to RestQueryServlet. Update its <servlet-class> from com.esri.gpt.control.georss.RestQueryServlet to gpt.search.CustomRestQueryServlet, as shown below. Then, save the file.<servlet>
<servlet-name>RestQueryServlet</servlet-name>
<servlet-class>gpt.search.CustomRestQueryServlet</servlet-class>
<init-param>
<param-name>bundleBaseName</param-name>
<param-value>gpt.resources.gpt</param-value>
</init-param>
<load-on-startup>6</load-on-startup>
</servlet>
Adapt the Additional Options web page
The criteria.jsp file defines the pop-up interface for Additional Options on the Search page. Now that you've created the filter and done the underlying work to get it referenced in the geoportal, it is important to add the field to this search interface. Follow the steps below.
- Navigate to the \\geoportal\catalog\searchdirectory and open the criteria.jsp file in a text editor.
- In the criteria.jsp file, find the section where the Modified Date search is defined. You will insert your custom search field code just below the whole <%//modification date %> section. Note that the value defined for the outputText id=scLbl will be a string that will need to be referenced in the gpt.properties file. This string defines the label for your field in the Additional Options interface.
- After the final </h:panelGroup> tag in
the modification date section, insert the following (substituting
your element for the lineage one here):
<% // lineage (added) %> <h:outputText id="txtClearHtml" escape="false" value=" "/> <h:outputText escape="false" value="<h3>"/> <h:outputText id="scLblLineage" value="#{gptMsg['catalog.search.filterLineage.title']}" /> <h:outputText escape="false" value="</h3>"/> <h:inputText id="scLineage" onchange="javascript:updateHiddenValue(this)" value="#{SearchFilterLineage.lineage}" maxlength="4000" styleClass="searchBox" />
- Near the end of the criteria.jsp file, there is a section that further defines the search options on the Additional Options dialog. Add a value for your newly added search option, beneath the h:inputHidden id="scSelThemeHidden" tag in the list, as shown below. Note that the id for your inputHidden tag should be similar to the id in the <h:inputText> element in the first piece of code you added to this file. In our example for the inputText element, the id was scLineage. In this h:inputHidden element, the id will be scLineageHidden:
<h:outputText escape="false" value="</div>"/> <h:inputHidden id="scSelSortHidden" value="#{SearchFilterSort.selectedSort}"/> <h:inputHidden id="scDateToHidden" value="#{SearchFilterTemporal.dateModifiedTo}"/> <h:inputHidden id="scDateFromHidden" value="#{SearchFilterTemporal.dateModifiedFrom}"/> <h:inputHidden id="scSelContentHidden" value="#{SearchFilterContentTypes.selectedContentType}"/> <h:inputHidden id="scSelThemeHidden" value="#{SearchFilterThemeTypes.selectedThemes}"> <h:inputHidden id="scLineageHidden" value="#{SearchFilterLineage.lineage}"/>
- Scroll up in the criteria.jsp file to find the javascript function scReadRestUrlParams(). Add your metadata element's (lineage, in our example) parameters that will be appended to the generated REST URLs:
function scReadRestUrlParams() { … var scLineage = GptUtils.valChkStr( dojo.byId('frmSearchCriteria:scLineageHidden').value); if(scText != "") { restParams += "&lineage=" + encodeURIComponent(scLineage); } … }
- Save the criteria.jsp file.
Update gpt.properties with a label for your new search filter
- Navigate to the \\geoportal\WEB-INF\classes\gpt\resources directory and open the gpt.properties file in a text editor.
- Search for the section where search filters are defined. Keys for search filters begin with the string catalog.search.filter…
- Add a new value. This value should match the scLbl string you defined in your h:outputText id=scLbl element from the criteria.jsp file. In our example, we add the following:
catalog.search.filterLineage.title = Lineage
- Save the gpt.properties file.
Restart the geoportal web application for your changes to take affect. You should be able to launch the Additional Options dialog and see a field for your new search filter. When you input text for that filter and click ok, then click the search button, results should contain your input text in that element of the metadata document.