mirror of
https://github.com/Alfresco/alfresco-community-repo.git
synced 2025-08-07 17:49:17 +00:00
Merged HEAD-BUG-FIX (5.0/Cloud) to HEAD (5.0/Cloud)
84919: Merged PLATFORM1 (5.0/Cloud) to HEAD-BUG-FIX (5.0/Cloud) 83447: ACE-2612: Initial implementation of the Suggester service to support the auto-suggest web script. git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@85237 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
@@ -1408,6 +1408,20 @@
|
|||||||
<bean id="nameChecker" class="org.alfresco.repo.dictionary.constraint.NameChecker">
|
<bean id="nameChecker" class="org.alfresco.repo.dictionary.constraint.NameChecker">
|
||||||
<property name="dictionaryService" ref="dictionaryService" />
|
<property name="dictionaryService" ref="dictionaryService" />
|
||||||
</bean>
|
</bean>
|
||||||
|
|
||||||
|
<bean id="suggesterService" class="org.alfresco.repo.management.subsystems.SubsystemProxyFactory">
|
||||||
|
<property name="sourceApplicationContextFactory">
|
||||||
|
<ref bean="Search" />
|
||||||
|
</property>
|
||||||
|
<property name="sourceBeanName">
|
||||||
|
<value>search.suggesterService</value>
|
||||||
|
</property>
|
||||||
|
<property name="interfaces">
|
||||||
|
<list>
|
||||||
|
<value>org.alfresco.service.cmr.search.SuggesterService</value>
|
||||||
|
</list>
|
||||||
|
</property>
|
||||||
|
</bean>
|
||||||
|
|
||||||
<!-- Custom property editors -->
|
<!-- Custom property editors -->
|
||||||
<bean class="org.springframework.beans.factory.config.CustomEditorConfigurer">
|
<bean class="org.springframework.beans.factory.config.CustomEditorConfigurer">
|
||||||
|
@@ -299,5 +299,14 @@
|
|||||||
<ref bean="search.indexerAndSearcherFactory" />
|
<ref bean="search.indexerAndSearcherFactory" />
|
||||||
</property>
|
</property>
|
||||||
</bean>
|
</bean>
|
||||||
|
|
||||||
|
<bean id="search.suggesterService" class="org.alfresco.repo.search.impl.solr.SolrSuggesterServiceImpl">
|
||||||
|
<property name="enabled">
|
||||||
|
<value>${solr.suggester.enabled}</value>
|
||||||
|
</property>
|
||||||
|
<property name="solrAdminHTTPClient">
|
||||||
|
<ref bean="search.solrAdminHTTPCLient" />
|
||||||
|
</property>
|
||||||
|
</bean>
|
||||||
|
|
||||||
</beans>
|
</beans>
|
||||||
|
@@ -4,3 +4,7 @@ solr.port.ssl=8443
|
|||||||
solr.query.includeGroupsForRoleAdmin=false
|
solr.query.includeGroupsForRoleAdmin=false
|
||||||
solr.query.maximumResultsFromUnlimitedQuery=${system.acl.maxPermissionChecks}
|
solr.query.maximumResultsFromUnlimitedQuery=${system.acl.maxPermissionChecks}
|
||||||
solr.baseUrl=/solr
|
solr.baseUrl=/solr
|
||||||
|
#
|
||||||
|
# Solr Suggester properties
|
||||||
|
#
|
||||||
|
solr.suggester.enabled=true
|
@@ -298,6 +298,15 @@
|
|||||||
<property name="searcher">
|
<property name="searcher">
|
||||||
<ref bean="search.indexerAndSearcherFactory" />
|
<ref bean="search.indexerAndSearcherFactory" />
|
||||||
</property>
|
</property>
|
||||||
</bean>
|
</bean>
|
||||||
|
|
||||||
|
<bean id="search.suggesterService" class="org.alfresco.repo.search.impl.solr.SolrSuggesterServiceImpl">
|
||||||
|
<property name="enabled">
|
||||||
|
<value>${solr.suggester.enabled}</value>
|
||||||
|
</property>
|
||||||
|
<property name="solrAdminHTTPClient">
|
||||||
|
<ref bean="search.solrAdminHTTPCLient" />
|
||||||
|
</property>
|
||||||
|
</bean>
|
||||||
|
|
||||||
</beans>
|
</beans>
|
||||||
|
@@ -4,3 +4,7 @@ solr.port.ssl=8446
|
|||||||
solr.query.includeGroupsForRoleAdmin=false
|
solr.query.includeGroupsForRoleAdmin=false
|
||||||
solr.query.maximumResultsFromUnlimitedQuery=${system.acl.maxPermissionChecks}
|
solr.query.maximumResultsFromUnlimitedQuery=${system.acl.maxPermissionChecks}
|
||||||
solr.baseUrl=/solr4
|
solr.baseUrl=/solr4
|
||||||
|
#
|
||||||
|
# Solr Suggester properties
|
||||||
|
#
|
||||||
|
solr.suggester.enabled=true
|
@@ -0,0 +1,123 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2005-2014 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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.alfresco.repo.search.impl.lucene;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.alfresco.service.cmr.search.SuggesterResult;
|
||||||
|
import org.alfresco.util.Pair;
|
||||||
|
import org.alfresco.util.ParameterCheck;
|
||||||
|
import org.apache.commons.logging.Log;
|
||||||
|
import org.apache.commons.logging.LogFactory;
|
||||||
|
import org.json.JSONArray;
|
||||||
|
import org.json.JSONException;
|
||||||
|
import org.json.JSONObject;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Jamal Kaabi-Mofrad
|
||||||
|
* @since 5.0
|
||||||
|
*/
|
||||||
|
public class SolrSuggesterResult implements SuggesterResult
|
||||||
|
{
|
||||||
|
private static final Log logger = LogFactory.getLog(SolrSuggesterResult.class);
|
||||||
|
|
||||||
|
private Long numberFound;
|
||||||
|
private List<Pair<String, Integer>> suggestions = new ArrayList<>();
|
||||||
|
|
||||||
|
public SolrSuggesterResult()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public SolrSuggesterResult(JSONObject jsonObject)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
processJson(jsonObject);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
logger.info(e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses the json returned from the suggester
|
||||||
|
*
|
||||||
|
* @param json the JSON object
|
||||||
|
* @throws JSONException
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("rawtypes")
|
||||||
|
protected void processJson(JSONObject json) throws JSONException
|
||||||
|
{
|
||||||
|
ParameterCheck.mandatory("json", json);
|
||||||
|
|
||||||
|
if (logger.isDebugEnabled())
|
||||||
|
{
|
||||||
|
logger.debug("Suggester JSON response: " + json);
|
||||||
|
}
|
||||||
|
|
||||||
|
JSONObject suggest = json.getJSONObject("suggest");
|
||||||
|
for (Iterator suggestIterator = suggest.keys(); suggestIterator.hasNext(); /**/)
|
||||||
|
{
|
||||||
|
String dictionary = (String) suggestIterator.next();
|
||||||
|
|
||||||
|
JSONObject dictionaryJsonObject = suggest.getJSONObject(dictionary);
|
||||||
|
for (Iterator dicIterator = dictionaryJsonObject.keys(); dicIterator.hasNext(); /**/)
|
||||||
|
{
|
||||||
|
String termStr = (String) dicIterator.next();
|
||||||
|
|
||||||
|
JSONObject termJsonObject = dictionaryJsonObject.getJSONObject(termStr);
|
||||||
|
// number found
|
||||||
|
this.numberFound = termJsonObject.getLong("numFound");
|
||||||
|
|
||||||
|
// the suggested terms
|
||||||
|
JSONArray suggestion = termJsonObject.getJSONArray("suggestions");
|
||||||
|
for (int i = 0, length = suggestion.length(); i < length; i++)
|
||||||
|
{
|
||||||
|
JSONObject data = suggestion.getJSONObject(i);
|
||||||
|
this.suggestions.add(new Pair<String, Integer>(data.getString("term"), data.getInt("weight")));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getNumberFound()
|
||||||
|
{
|
||||||
|
return this.numberFound;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<Pair<String, Integer>> getSuggestions()
|
||||||
|
{
|
||||||
|
return this.suggestions;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString()
|
||||||
|
{
|
||||||
|
StringBuilder builder = new StringBuilder(250);
|
||||||
|
builder.append("SolrSuggesterResult [numberFound=").append(this.numberFound).append(", suggestions=")
|
||||||
|
.append(this.suggestions).append("]");
|
||||||
|
return builder.toString();
|
||||||
|
}
|
||||||
|
}
|
@@ -106,19 +106,28 @@ public class SolrAdminHTTPClient
|
|||||||
this.httpClientFactory = httpClientFactory;
|
this.httpClientFactory = httpClientFactory;
|
||||||
}
|
}
|
||||||
|
|
||||||
public JSONObject execute(HashMap<String, String>args)
|
public JSONObject execute(HashMap<String, String> args)
|
||||||
{
|
{
|
||||||
|
return execute(adminUrl, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
public JSONObject execute(String relativeHandlerPath, HashMap<String, String> args)
|
||||||
|
{
|
||||||
|
ParameterCheck.mandatory("relativeHandlerPath", relativeHandlerPath);
|
||||||
|
ParameterCheck.mandatory("args", args);
|
||||||
|
|
||||||
|
String path = getPath(relativeHandlerPath);
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
URLCodec encoder = new URLCodec();
|
URLCodec encoder = new URLCodec();
|
||||||
StringBuilder url = new StringBuilder();
|
StringBuilder url = new StringBuilder();
|
||||||
|
|
||||||
for(String key : args.keySet())
|
for (String key : args.keySet())
|
||||||
{
|
{
|
||||||
String value = args.get(key);
|
String value = args.get(key);
|
||||||
if(url.length() == 0)
|
if (url.length() == 0)
|
||||||
{
|
{
|
||||||
url.append(adminUrl);
|
url.append(path);
|
||||||
url.append("?");
|
url.append("?");
|
||||||
url.append(encoder.encode(key, "UTF-8"));
|
url.append(encoder.encode(key, "UTF-8"));
|
||||||
url.append("=");
|
url.append("=");
|
||||||
@@ -129,27 +138,27 @@ public class SolrAdminHTTPClient
|
|||||||
url.append("&");
|
url.append("&");
|
||||||
url.append(encoder.encode(key, "UTF-8"));
|
url.append(encoder.encode(key, "UTF-8"));
|
||||||
url.append("=");
|
url.append("=");
|
||||||
url.append(encoder.encode(value, "UTF-8"));
|
url.append(encoder.encode(value, "UTF-8"));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//PostMethod post = new PostMethod(url.toString());
|
// PostMethod post = new PostMethod(url.toString());
|
||||||
GetMethod get = new GetMethod(url.toString());
|
GetMethod get = new GetMethod(url.toString());
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
httpClient.executeMethod(get);
|
httpClient.executeMethod(get);
|
||||||
|
|
||||||
if(get.getStatusCode() == HttpStatus.SC_MOVED_PERMANENTLY || get.getStatusCode() == HttpStatus.SC_MOVED_TEMPORARILY)
|
if (get.getStatusCode() == HttpStatus.SC_MOVED_PERMANENTLY || get.getStatusCode() == HttpStatus.SC_MOVED_TEMPORARILY)
|
||||||
{
|
{
|
||||||
Header locationHeader = get.getResponseHeader("location");
|
Header locationHeader = get.getResponseHeader("location");
|
||||||
if (locationHeader != null)
|
if (locationHeader != null)
|
||||||
{
|
{
|
||||||
String redirectLocation = locationHeader.getValue();
|
String redirectLocation = locationHeader.getValue();
|
||||||
get.setURI(new URI(redirectLocation, true));
|
get.setURI(new URI(redirectLocation, true));
|
||||||
httpClient.executeMethod(get);
|
httpClient.executeMethod(get);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (get.getStatusCode() != HttpServletResponse.SC_OK)
|
if (get.getStatusCode() != HttpServletResponse.SC_OK)
|
||||||
@@ -185,4 +194,20 @@ public class SolrAdminHTTPClient
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private String getPath(String path)
|
||||||
|
{
|
||||||
|
if (path.startsWith(baseUrl))
|
||||||
|
{
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
else if (path.startsWith("/"))
|
||||||
|
{
|
||||||
|
return baseUrl + path;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return baseUrl + '/' + path;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -0,0 +1,87 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2005-2014 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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.alfresco.repo.search.impl.solr;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
|
||||||
|
import org.alfresco.error.AlfrescoRuntimeException;
|
||||||
|
import org.alfresco.repo.search.impl.lucene.SolrSuggesterResult;
|
||||||
|
import org.alfresco.service.cmr.search.SuggesterResult;
|
||||||
|
import org.alfresco.service.cmr.search.SuggesterService;
|
||||||
|
import org.json.JSONObject;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Solr Suggester Service Implementation.
|
||||||
|
*
|
||||||
|
* @author Jamal Kaabi-Mofrad
|
||||||
|
* @since 5.0
|
||||||
|
*/
|
||||||
|
public class SolrSuggesterServiceImpl implements SuggesterService
|
||||||
|
{
|
||||||
|
|
||||||
|
public static final String SUGGESER_PATH = "/alfresco/suggest";
|
||||||
|
|
||||||
|
private boolean enabled;
|
||||||
|
private SolrAdminHTTPClient solrAdminHTTPClient;
|
||||||
|
|
||||||
|
public void setEnabled(boolean isEnabled)
|
||||||
|
{
|
||||||
|
this.enabled = isEnabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSolrAdminHTTPClient(SolrAdminHTTPClient solrAdminHTTPClient)
|
||||||
|
{
|
||||||
|
this.solrAdminHTTPClient = solrAdminHTTPClient;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isEnabled()
|
||||||
|
{
|
||||||
|
return this.enabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SuggesterResult getSuggestions(String term, int limit)
|
||||||
|
{
|
||||||
|
// if it is not enabled, return an empty result set
|
||||||
|
if (!enabled)
|
||||||
|
{
|
||||||
|
return new SolrSuggesterResult();
|
||||||
|
}
|
||||||
|
try
|
||||||
|
{
|
||||||
|
HashMap<String, String> params = new HashMap<>(3);
|
||||||
|
params.put("q", term);
|
||||||
|
if (limit > 0)
|
||||||
|
{
|
||||||
|
params.put("suggest.count", Integer.toString(limit));
|
||||||
|
}
|
||||||
|
params.put("wt", "json");
|
||||||
|
|
||||||
|
JSONObject response = solrAdminHTTPClient.execute(SUGGESER_PATH, params);
|
||||||
|
return new SolrSuggesterResult(response);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
throw new AlfrescoRuntimeException("SolrSuggester failed.", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@@ -0,0 +1,48 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2005-2014 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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.alfresco.service.cmr.search;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.alfresco.util.Pair;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Term suggestions response object
|
||||||
|
*
|
||||||
|
* @author Jamal Kaabi-Mofrad
|
||||||
|
* @since 5.0
|
||||||
|
*/
|
||||||
|
public interface SuggesterResult
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the number of suggestions
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
long getNumberFound();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the list of suggestions as ("term", "weight") pairs. Never <i>null</i>.
|
||||||
|
*
|
||||||
|
* @return list of suggestions
|
||||||
|
*/
|
||||||
|
List<Pair<String, Integer>> getSuggestions();
|
||||||
|
}
|
@@ -0,0 +1,46 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2005-2014 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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.alfresco.service.cmr.search;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A service that returns term suggestions
|
||||||
|
*
|
||||||
|
* @author Jamal Kaabi-Mofrad
|
||||||
|
* @since 5.0
|
||||||
|
*/
|
||||||
|
public interface SuggesterService
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether the Suggester is enabled (refer to 'solr.suggester.enabled' repository property) or not
|
||||||
|
*
|
||||||
|
* @return true if the Suggester is enabled, false otherwise
|
||||||
|
*/
|
||||||
|
public boolean isEnabled();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get suggestions for the specified term
|
||||||
|
*
|
||||||
|
* @param term the term to use for the search
|
||||||
|
* @param limit the number of suggestions for Solr to return
|
||||||
|
* @return term suggestions result. Never <i>null</i>
|
||||||
|
*/
|
||||||
|
public SuggesterResult getSuggestions(String term, int limit);
|
||||||
|
}
|
Reference in New Issue
Block a user