package gw.solr.utils uses com.guidewire.pl.system.dependency.PLDependencies uses gw.solr.SolrException uses gw.solr.schema.SolrSchemaConfigReader uses gw.xml.XmlElement uses org.apache.solr.client.solrj.SolrQuery uses java.io.File uses java.lang.Integer uses java.lang.Exception uses java.util.HashMap uses java.util.LinkedHashMap uses java.util.Map @ReadOnly class PLSolrUtils { /** * Name of application ID field in Solr */ public static final var APPID_TAG : String = "appId" /** * Name of document ID field in Solr */ public static final var DOCUMENTID_TAG : String = "documentId" /** * Name of URN field in Solr */ public static final var URN_TAG : String = "urn" /** * JSON keys for consistency versioning */ public final static var CONSISTENCY_TAG : String ="$Consistency$" public final static var VERSIONS_TAG : String = "$BeanVersions$" public final static var OPERATION_TAG : String = "$Operation$" public final static var BEAN_TYPE_TAG : String = "type" public final static var BEAN_PUBLIC_ID_TAG : String = "pid" public final static var BEAN_ID_TAG : String = "id" public final static var BEAN_VERSION_TAG : String = "ver" /** * Solr commands and constants */ public final static var SOLR_UPDATE : String = "update" public final static var SOLR_DELETE : String = "delete" public static final var SOLR_ID_TAG : String = "id" public final static var SOLR_QUERY : String = "query" public final static var SOLR_COMMIT : String = "commit" /** * Cache of solr schema readers. Not used in dev mode. */ static final var _schemaCache = new HashMap() static final var _schemaCacheEnabled = PLDependencies.ServerMode.Production /** * Constructs a search url for the specified query * * @param searchQuery the query to execute * @param searchFilter the query filter to apply * @param groupField field to group results by or null * @param groupLimit maximum results to retrieve per group * @param fetchSize number of records to fetch * @param debug if true, tells Solr to dump diagnostics on this query including * an explanation of the scoring. Very useful during development but a huge * performance penalty. Do not use in production. * * @return complete solr url for this query */ static function buildSearchParams(searchQuery : String, searchFilter : String, groupField : String, groupLimit : int, fetchSize : int, debug : boolean) : SolrQuery { var argMap = buildDefaultArgMap(debug) argMap.put("q", searchQuery) argMap.put("fq", searchFilter) if(groupField != null && groupField.length() > 0) { argMap.put("group", "true") // argMap.put("group.format", "simple") argMap.put("group.main", "true") argMap.put("group.field", groupField) argMap.put("group.limit", Integer.toString(groupLimit)) } argMap.put("start", "0") argMap.put("rows", Integer.toString(fetchSize)) argMap.put("fl", "*,score") var solrQuery = new SolrQuery() for(entry in argMap.entrySet()) { solrQuery.setParam(entry.Key, { entry.Value }) } return solrQuery } /** * Constructs a search url for the specified query * * @param searchQuery the query to execute * @param searchFilter the query filter to apply * @param groupField field to group results by or null * @param groupLimit maximum results to retrieve per group * @param sortOrder fields and direction sort by * @param fetchStart index of first record desired result set * @param fetchSize number of records to fetch * @param debug if true, tells Solr to dump diagnostics on this query including * an explanation of the scoring. Very useful during development but a huge * performance penalty. Do not use in production. * * @return complete solr url for this query */ static function buildPagingSearchParams(searchQuery : String, searchFilter : String, groupField : String, groupLimit : int, sortOrder : String, fetchStart: int, fetchSize : int, debug : boolean) : SolrQuery { var argMap = buildDefaultArgMap(debug) argMap.put("q", searchQuery) argMap.put("fq", searchFilter) if(groupField != null && groupField.length() > 0) { argMap.put("group", "true") // argMap.put("group.format", "simple") argMap.put("group.main", "true") argMap.put("group.field", groupField) argMap.put("group.limit", Integer.toString(groupLimit)) } argMap.put("sort", sortOrder) argMap.put("start", Integer.toString(fetchStart)) argMap.put("rows", Integer.toString(fetchSize)) argMap.put("fl", "*,score") var solrQuery = new SolrQuery() for(entry in argMap.entrySet()) { solrQuery.setParam(entry.Key, { entry.Value }) } return solrQuery } /** * Constructs a search url that retrieves all matching records for a simple query in json format. * Used for managing document updates when active and archived documents are in separate data stores. * * @param searchQuery the query to execute * @param debug if true, tells Solr to dump diagnostics on this query including * an explanation of the scoring. Very useful during development but a huge * performance penalty. Do not use in production. * * @return complete solr url for this query */ static function buildArchiveSearchParams(searchQuery: String, debug : boolean) : SolrQuery { var argMap = buildDefaultArgMap(debug) argMap.put("q", searchQuery) argMap.put("start", "0") argMap.put("fl", "*") // argMap.put("wt", "json") var solrQuery = new SolrQuery() for(entry in argMap.entrySet()) { solrQuery.setParam(entry.Key, { entry.Value }) } return solrQuery } private static function buildDefaultArgMap(debug : boolean) : Map { var argMap = new LinkedHashMap() argMap.put("q", null) argMap.put("fq", null) argMap.put("sort", null) argMap.put("version", "2.2") argMap.put("start", null) argMap.put("rows", null) argMap.put("fl", null) argMap.put("wt", null) if(debug) { argMap.put("indent", "on") argMap.put("debugQuery", "true") } return argMap } /** * For interpreting XML formatted Solr results. Retrieves the first child node * where the "name" attribute has the specfied value. * * @param node parent node to get child from * @param value value to match with that of attribute * @return child node whose name attribute is 'fieldName' */ static function getNamedChild(node : XmlElement, name : String) : XmlElement { return getChildByAttribute(node, "name", name) } /** * For interpreting XML formatted Solr results. Retrieves the first child node * where the specified attribute has the specfied value. * * @param node parent node to get child from * @param attrname name of attribute to check * @param value value to match with that of attribute * @return child node whose name attribute is 'fieldName' */ static function getChildByAttribute(node : XmlElement, attrName : String, value : String) : XmlElement { return node.$Children.firstWhere(\ x -> x.getAttributeValue(attrName) == value) } /** * For interpreting XML formatted Solr results. Checks that the node type (e.g. tag name) * of the specified element matches the type passed in. * * @param node node on which to check the type * @param type type name to match, e.g str, date, float, arr, etc. * @return true if the tag name of this node matches the specified type, false otherwise. */ static function isType(node : XmlElement, type : String) : boolean { return node != null && node.$QName.LocalPart.equals(type) } /** * If condition is not true, throws an exception with the specified message. * * @param condition true for valid, false otherwise * @param msg message to use if validation fails. */ static function validate(condition : boolean, msg : String) { if(!condition) { throw new Exception(msg) } } /** * If condition is not true, throws an exception with the specified message * where message is lazily computed by the passed in block * * @param condition true for valid, false otherwise * @param blk block returning the message to use if validation fails. */ static function validateLazyMsg(condition : boolean, blk() : String ) { if(!condition) { throw new Exception(blk()) } } /** * Retrieve the SolrSchemaConfigReader for the specified config file. * Cached in production but read from disk each time in dev mode. * * @param solr-search-config file to read * @return a validated instance of the SolrSchemaConfigReader for this document */ static function getSchemaConfigReader( configFile : File ) : SolrSchemaConfigReader { var result = _schemaCache.get(configFile) if(result == null) { result = new SolrSchemaConfigReader(configFile) result.validate() if(_schemaCacheEnabled) { _schemaCache.put(configFile, result) } } return result } /** * Utility method to ensure an exception is propagated upward typed as * gw.solr.SolrException. Exceptions that are the correct type are simply * thrown. All others are wrapped as SolrException and then thrown. * * @param e the exception to be wrapped * @throws SolrException */ public static function wrapAndThrow(e : Exception) { if (e typeis SolrException) { throw e } else { throw new SolrException(e) } } }