From 5018fee2261a9827b0fc07aa6c013b09df793203 Mon Sep 17 00:00:00 2001 From: Andrew Hind Date: Thu, 23 Jun 2011 14:22:40 +0000 Subject: [PATCH] ALF-8910: RSOLR 037: Integrate CMIS Query Parser into SOLR engine - added solr-cmis query language git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@28541 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261 --- config/alfresco/core-services-context.xml | 16 + .../impl/lucene/SolrCMISQueryLanguage.java | 300 ++++++++++++++++++ 2 files changed, 316 insertions(+) create mode 100644 source/java/org/alfresco/repo/search/impl/lucene/SolrCMISQueryLanguage.java diff --git a/config/alfresco/core-services-context.xml b/config/alfresco/core-services-context.xml index 5d516945fa..d66af6e745 100644 --- a/config/alfresco/core-services-context.xml +++ b/config/alfresco/core-services-context.xml @@ -630,6 +630,22 @@ + + + + + + + + + + + + + + + + diff --git a/source/java/org/alfresco/repo/search/impl/lucene/SolrCMISQueryLanguage.java b/source/java/org/alfresco/repo/search/impl/lucene/SolrCMISQueryLanguage.java new file mode 100644 index 0000000000..af91bf1385 --- /dev/null +++ b/source/java/org/alfresco/repo/search/impl/lucene/SolrCMISQueryLanguage.java @@ -0,0 +1,300 @@ +/* + * Copyright (C) 2005-2010 Alfresco Software Limited. + * + * This file is part of Alfresco + * + * Alfresco is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Alfresco is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + */ +package org.alfresco.repo.search.impl.lucene; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.Reader; +import java.io.UnsupportedEncodingException; +import java.util.List; +import java.util.Locale; + +import javax.servlet.http.HttpServletResponse; + +import org.alfresco.repo.domain.node.NodeDAO; +import org.alfresco.repo.security.authentication.AuthenticationUtil; +import org.alfresco.service.cmr.repository.datatype.DefaultTypeConverter; +import org.alfresco.service.cmr.search.ResultSet; +import org.alfresco.service.cmr.search.ResultSetRow; +import org.alfresco.service.cmr.search.SearchParameters; +import org.alfresco.service.cmr.search.SearchService; +import org.alfresco.service.cmr.search.SearchParameters.SortDefinition; +import org.alfresco.service.cmr.security.PermissionService; +import org.apache.commons.codec.net.URLCodec; +import org.apache.commons.httpclient.HttpClient; +import org.apache.commons.httpclient.HttpException; +import org.apache.commons.httpclient.UsernamePasswordCredentials; +import org.apache.commons.httpclient.auth.AuthScope; +import org.apache.commons.httpclient.methods.ByteArrayRequestEntity; +import org.apache.commons.httpclient.methods.PostMethod; +import org.apache.commons.httpclient.methods.RequestEntity; +import org.apache.commons.httpclient.params.HttpClientParams; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; +import org.json.JSONTokener; +import org.springframework.extensions.surf.util.I18NUtil; + +/** + * @author Andy + */ +public class SolrCMISQueryLanguage implements LuceneQueryLanguageSPI +{ + static Log s_logger = LogFactory.getLog(SolrCMISQueryLanguage.class); + + private NodeDAO nodeDAO; + + private PermissionService permissionService; + + /** + * @param nodeDAO the nodeDAO to set + */ + public void setNodeDAO(NodeDAO nodeDAO) + { + this.nodeDAO = nodeDAO; + } + + /** + * @param permissionService the permissionService to set + */ + public void setPermissionService(PermissionService permissionService) + { + this.permissionService = permissionService; + } + + /* + * (non-Javadoc) + * @seeorg.alfresco.repo.search.impl.lucene.LuceneQueryLanguageSPI#executeQuery(org.alfresco.service.cmr.search. + * SearchParameters, org.alfresco.repo.search.impl.lucene.ADMLuceneSearcherImpl) + */ + @Override + public ResultSet executeQuery(SearchParameters searchParameters, ADMLuceneSearcherImpl admLuceneSearcher) + { + try + { + HttpClient httpClient = new HttpClient(); + httpClient.getParams().setBooleanParameter(HttpClientParams.PREEMPTIVE_AUTHENTICATION, true); + httpClient.getState().setCredentials(new AuthScope(AuthScope.ANY_HOST, AuthScope.ANY_PORT), new UsernamePasswordCredentials("admin", "admin")); + + StringBuilder url = new StringBuilder("http://localhost:8080/solr/alfresco/cmis"); + //duplicate the query in the URL + url.append("?q="); + URLCodec encoder = new URLCodec(); + url.append(encoder.encode(searchParameters.getQuery(), "UTF-8")); + url.append("&wt=json"); + url.append("&fl=*,score"); + if(searchParameters.getMaxItems() > 0) + { + url.append("&rows=").append(searchParameters.getMaxItems()); + } + else + { + url.append("&rows=").append(Integer.MAX_VALUE); + } + url.append("&df=").append(searchParameters.getDefaultFieldName()); + url.append("&start=").append(searchParameters.getSkipCount()); + + Locale locale = I18NUtil.getLocale(); + if(searchParameters.getLocales().size() > 0) + { + locale = searchParameters.getLocales().get(0); + } + url.append("&locale="); + encoder = new URLCodec(); + url.append(encoder.encode(locale.toString(), "UTF-8")); + + + // Will use this search if not specified as part of the query )no order by clause) + // If the query contains an order by clause this will be used instead. + StringBuffer sortBuffer = new StringBuffer(); + for(SortDefinition sortDefinition : searchParameters.getSortDefinitions()) + { + if(sortBuffer.length() == 0) + { + sortBuffer.append("&sort="); + } + else + { + sortBuffer.append(", "); + } + sortBuffer.append(sortDefinition.getField()).append(" "); + if(sortDefinition.isAscending()) + { + sortBuffer.append("asc"); + } + else + { + sortBuffer.append("desc"); + } + + } + url.append(sortBuffer); + + // Authorities go over in body + + StringBuilder authQuery = new StringBuilder(); + for(String authority : permissionService.getAuthorisations()) + { + if(authQuery.length() > 0) + { + authQuery.append(" "); + } + authQuery.append("AUTHORITY:\"").append(authority).append("\""); + } + + //url.append("&fq="); + //encoder = new URLCodec(); + //url.append(encoder.encode(authQuery.toString(), "UTF-8")); + + url.append("&fq="); + url.append(encoder.encode("{!afts}", "UTF-8")); + url.append("AUTHORITY_FILTER_FROM_JSON"); + + // facets would go on url? + + JSONObject body = new JSONObject(); + body.put("query", searchParameters.getQuery()); + //body.put("defaultField", searchParameters.getDefaultFieldName()); + + body.put("filter", authQuery); + + JSONArray locales = new JSONArray(); + for(Locale currentLocale : searchParameters.getLocales()) + { + locales.put(DefaultTypeConverter.INSTANCE.convert(String.class, currentLocale)); + } + if(locales.length() == 0) + { + locales.put(I18NUtil.getLocale()); + } + body.put("locales", locales); + + + // templates etc may affect CONTAINS() clause + JSONArray templates = new JSONArray(); + for(String templateName : searchParameters.getQueryTemplates().keySet()) + { + JSONObject template = new JSONObject(); + template.put("name", templateName); + template.put("template", searchParameters.getQueryTemplates().get(templateName)); + templates.put(template); + } + body.put("templates", templates); + + JSONArray allAttributes = new JSONArray(); + for(String attribute : searchParameters.getAllAttributes()) + { + allAttributes.put(attribute); + } + body.put("allAttributes", allAttributes); + + body.put("defaultFTSOperator", searchParameters.getDefaultFTSOperator()); + body.put("defaultFTSFieldOperator", searchParameters.getDefaultFTSFieldOperator()); + if(searchParameters.getMlAnalaysisMode() != null) + { + body.put("mlAnalaysisMode", searchParameters.getMlAnalaysisMode().toString()); + } + body.put("defaultNamespace", searchParameters.getNamespace()); + + + JSONArray textAttributes = new JSONArray(); + for(String attribute : searchParameters.getTextAttributes()) + { + textAttributes.put(attribute); + } + body.put("textAttributes", textAttributes); + + PostMethod post = new PostMethod(url.toString()); + post.setRequestEntity(new ByteArrayRequestEntity(body.toString().getBytes("UTF-8"), "application/json")); + + httpClient.executeMethod(post); + + if (post.getStatusCode() != HttpServletResponse.SC_OK) + { + throw new LuceneQueryParserException("Request failed " + post.getStatusCode()+" "+url.toString()); + } + + + Reader reader = new BufferedReader(new InputStreamReader(post.getResponseBodyAsStream())); + // TODO - replace with streaming-based solution e.g. SimpleJSON ContentHandler + JSONObject json = new JSONObject(new JSONTokener(reader)); + SolrJSONResultSet results = new SolrJSONResultSet(json, nodeDAO, searchParameters); + if(s_logger.isDebugEnabled()) + { + s_logger.debug("Sent :"+url); + s_logger.debug(" with: "+body.toString()); + s_logger.debug("Got: "+results.getNumberFound()+ " in "+results.getQueryTime()+ " ms"); + } + + return results; + } + catch (UnsupportedEncodingException e) + { + throw new LuceneQueryParserException("", e); + } + catch (HttpException e) + { + throw new LuceneQueryParserException("", e); + } + catch (IOException e) + { + throw new LuceneQueryParserException("", e); + } + catch (JSONException e) + { + throw new LuceneQueryParserException("", e); + } + } + + public String getName() + { + return SearchService.LANGUAGE_SOLR_CMIS; + } + + public void setFactories(List factories) + { + for (AbstractLuceneIndexerAndSearcherFactory factory : factories) + { + factory.registerQueryLanguage(this); + } + } + + public static void main(String[] args) + { + SolrCMISQueryLanguage solrAlfrescoFTSQueryLanguage = new SolrCMISQueryLanguage(); + SearchParameters sp = new SearchParameters(); + sp.setQuery("PATH:\"//.\""); + sp.setMaxItems(100); + sp.setSkipCount(12); + ResultSet rs = solrAlfrescoFTSQueryLanguage.executeQuery(sp, null); + System.out.println("Found "+rs.length()); + System.out.println("More "+rs.hasMore()); + System.out.println("Start "+rs.getStart()); + + for(ResultSetRow row : rs) + { + System.out.println("Score "+row.getScore()); + } + rs.close(); + } + +}