Tag cloud support

git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@7449 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
Andrew Hind
2007-11-27 16:20:01 +00:00
parent 08f0ed882c
commit 0b19ebb616
9 changed files with 317 additions and 77 deletions

View File

@@ -318,7 +318,7 @@
<!-- --> <!-- -->
<bean id="indexerAndSearcherFactory" class="org.alfresco.repo.service.StoreRedirectorProxyFactory"> <bean id="indexerAndSearcherFactory" class="org.alfresco.repo.service.StoreRedirectorProxyFactory">
<property name="proxyInterface"> <property name="proxyInterface">
<value>org.alfresco.repo.search.IndexerAndSearcher</value> <value>org.alfresco.repo.search.impl.lucene.LuceneIndexerAndSearcher</value>
</property> </property>
<property name="defaultBinding"> <property name="defaultBinding">
<ref bean="admLuceneIndexerAndSearcherFactory"></ref> <ref bean="admLuceneIndexerAndSearcherFactory"></ref>
@@ -502,6 +502,9 @@
<bean id="luceneCategoryService" class="org.alfresco.repo.search.impl.lucene.LuceneCategoryServiceImpl"> <bean id="luceneCategoryService" class="org.alfresco.repo.search.impl.lucene.LuceneCategoryServiceImpl">
<property name="nodeService"> <property name="nodeService">
<ref bean="nodeService" /> <ref bean="nodeService" />
</property>
<property name="publicNodeService">
<ref bean="NodeService" />
</property> </property>
<property name="tenantService"> <property name="tenantService">
<ref bean="tenantService"/> <ref bean="tenantService"/>

View File

@@ -668,7 +668,7 @@
<index enabled="true"> <index enabled="true">
<atomic>true</atomic> <atomic>true</atomic>
<stored>true</stored> <stored>true</stored>
<tokenised>true</tokenised> <tokenised>false</tokenised>
</index> </index>
</property> </property>
</properties> </properties>

View File

@@ -456,6 +456,8 @@
<!-- Category queries are filtered for nodes that are visible to the current user --> <!-- Category queries are filtered for nodes that are visible to the current user -->
<!-- Other methods are unrestricted at the moment --> <!-- Other methods are unrestricted at the moment -->
<!-- Uses the public node service for all mutations - access is allowed here and enforced by the public node service -->
<bean id="CategoryService_security" class="net.sf.acegisecurity.intercept.method.aopalliance.MethodSecurityInterceptor"> <bean id="CategoryService_security" class="net.sf.acegisecurity.intercept.method.aopalliance.MethodSecurityInterceptor">
<property name="authenticationManager"><ref bean="authenticationManager"/></property> <property name="authenticationManager"><ref bean="authenticationManager"/></property>
@@ -468,11 +470,12 @@
org.alfresco.service.cmr.search.CategoryService.getClassifications=AFTER_ACL_NODE.sys:base.ReadProperties org.alfresco.service.cmr.search.CategoryService.getClassifications=AFTER_ACL_NODE.sys:base.ReadProperties
org.alfresco.service.cmr.search.CategoryService.getRootCategories=AFTER_ACL_NODE.sys:base.ReadProperties org.alfresco.service.cmr.search.CategoryService.getRootCategories=AFTER_ACL_NODE.sys:base.ReadProperties
org.alfresco.service.cmr.search.CategoryService.getClassificationAspects=ACL_ALLOW org.alfresco.service.cmr.search.CategoryService.getClassificationAspects=ACL_ALLOW
org.alfresco.service.cmr.search.CategoryService.createClassifiction=ACL_METHOD.ROLE_ADMINISTRATOR org.alfresco.service.cmr.search.CategoryService.createClassifiction=ACL_ALLOW
org.alfresco.service.cmr.search.CategoryService.createRootCategory=ACL_METHOD.ROLE_ADMINISTRATOR org.alfresco.service.cmr.search.CategoryService.createRootCategory=ACL_ALLOW
org.alfresco.service.cmr.search.CategoryService.createCategory=ACL_METHOD.ROLE_ADMINISTRATOR org.alfresco.service.cmr.search.CategoryService.createCategory=ACL_ALLOW
org.alfresco.service.cmr.search.CategoryService.deleteClassification=ACL_METHOD.ROLE_ADMINISTRATOR org.alfresco.service.cmr.search.CategoryService.deleteClassification=ACL_ALLOW
org.alfresco.service.cmr.search.CategoryService.deleteCategory=ACL_METHOD.ROLE_ADMINISTRATOR org.alfresco.service.cmr.search.CategoryService.deleteCategory=ACL_ALLOW
org.alfresco.service.cmr.search.CategoryService.getTopCategories=ACL_ALLOW
</value> </value>
</property> </property>
</bean> </bean>

View File

@@ -28,8 +28,11 @@ import java.io.Serializable;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collection; import java.util.Collection;
import java.util.HashMap; import java.util.HashMap;
import java.util.List;
import java.util.Random; import java.util.Random;
import javax.transaction.NotSupportedException;
import javax.transaction.SystemException;
import javax.transaction.UserTransaction; import javax.transaction.UserTransaction;
import junit.framework.TestCase; import junit.framework.TestCase;
@@ -58,6 +61,7 @@ import org.alfresco.service.namespace.NamespaceService;
import org.alfresco.service.namespace.QName; import org.alfresco.service.namespace.QName;
import org.alfresco.service.transaction.TransactionService; import org.alfresco.service.transaction.TransactionService;
import org.alfresco.util.ApplicationContextHelper; import org.alfresco.util.ApplicationContextHelper;
import org.alfresco.util.Pair;
import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContext;
/** /**
@@ -282,7 +286,7 @@ public class ADMLuceneCategoryTest extends TestCase
genCatProp.setMandatory(true); genCatProp.setMandatory(true);
genCatProp.setMultiValued(true); genCatProp.setMultiValued(true);
genCatProp.setStoredInIndex(true); genCatProp.setStoredInIndex(true);
genCatProp.setTokenisedInIndex(true); genCatProp.setTokenisedInIndex(false);
genCatProp.setType("d:" + DataTypeDefinition.CATEGORY.getLocalName()); genCatProp.setType("d:" + DataTypeDefinition.CATEGORY.getLocalName());
assetClassCategorisationQName = QName.createQName(TEST_NAMESPACE, "AssetClass"); assetClassCategorisationQName = QName.createQName(TEST_NAMESPACE, "AssetClass");
@@ -294,7 +298,7 @@ public class ADMLuceneCategoryTest extends TestCase
acProp.setMandatory(true); acProp.setMandatory(true);
acProp.setMultiValued(true); acProp.setMultiValued(true);
acProp.setStoredInIndex(true); acProp.setStoredInIndex(true);
acProp.setTokenisedInIndex(true); acProp.setTokenisedInIndex(false);
acProp.setType("d:" + DataTypeDefinition.CATEGORY.getLocalName()); acProp.setType("d:" + DataTypeDefinition.CATEGORY.getLocalName());
investmentRegionCategorisationQName = QName.createQName(TEST_NAMESPACE, "InvestmentRegion"); investmentRegionCategorisationQName = QName.createQName(TEST_NAMESPACE, "InvestmentRegion");
@@ -306,7 +310,7 @@ public class ADMLuceneCategoryTest extends TestCase
irProp.setMandatory(true); irProp.setMandatory(true);
irProp.setMultiValued(true); irProp.setMultiValued(true);
irProp.setStoredInIndex(true); irProp.setStoredInIndex(true);
irProp.setTokenisedInIndex(true); irProp.setTokenisedInIndex(false);
irProp.setType("d:" + DataTypeDefinition.CATEGORY.getLocalName()); irProp.setType("d:" + DataTypeDefinition.CATEGORY.getLocalName());
marketingRegionCategorisationQName = QName.createQName(TEST_NAMESPACE, "MarketingRegion"); marketingRegionCategorisationQName = QName.createQName(TEST_NAMESPACE, "MarketingRegion");
@@ -318,7 +322,7 @@ public class ADMLuceneCategoryTest extends TestCase
mrProp.setMandatory(true); mrProp.setMandatory(true);
mrProp.setMultiValued(true); mrProp.setMultiValued(true);
mrProp.setStoredInIndex(true); mrProp.setStoredInIndex(true);
mrProp.setTokenisedInIndex(true); mrProp.setTokenisedInIndex(false);
mrProp.setType("d:" + DataTypeDefinition.CATEGORY.getLocalName()); mrProp.setType("d:" + DataTypeDefinition.CATEGORY.getLocalName());
dictionaryDAO.putModel(model); dictionaryDAO.putModel(model);
@@ -798,6 +802,52 @@ public class ADMLuceneCategoryTest extends TestCase
} }
public void testCatCount() throws Exception
{
TransactionService transactionService = serviceRegistry.getTransactionService();
UserTransaction tx = transactionService.getUserTransaction();
tx.begin();
assertEquals(1, categoryService.getChildren(catACBase , CategoryService.Mode.MEMBERS, CategoryService.Depth.IMMEDIATE).size());
assertEquals(2, categoryService.getChildren(catACBase , CategoryService.Mode.SUB_CATEGORIES, CategoryService.Depth.IMMEDIATE).size());
assertEquals(3, categoryService.getChildren(catACBase , CategoryService.Mode.ALL, CategoryService.Depth.IMMEDIATE).size());
assertEquals(14, categoryService.getChildren(catACBase , CategoryService.Mode.MEMBERS, CategoryService.Depth.ANY).size());
assertEquals(3, categoryService.getChildren(catACBase , CategoryService.Mode.SUB_CATEGORIES, CategoryService.Depth.ANY).size());
assertEquals(17, categoryService.getChildren(catACBase , CategoryService.Mode.ALL, CategoryService.Depth.ANY).size());
assertEquals(2, categoryService.getClassifications(rootNodeRef.getStoreRef()).size());
assertEquals(2, categoryService.getCategories(rootNodeRef.getStoreRef(), QName.createQName(TEST_NAMESPACE, "AssetClass"), CategoryService.Depth.IMMEDIATE).size());
assertEquals(3, categoryService.getCategories(rootNodeRef.getStoreRef(), QName.createQName(TEST_NAMESPACE, "AssetClass"), CategoryService.Depth.ANY).size());
assertEquals(6, categoryService.getClassificationAspects().size());
assertEquals(2, categoryService.getRootCategories(rootNodeRef.getStoreRef(), QName.createQName(TEST_NAMESPACE, "AssetClass")).size());
List<Pair<NodeRef, Integer>> top = categoryService.getTopCategories(rootNodeRef.getStoreRef(), QName.createQName(TEST_NAMESPACE, "AssetClass"), 10);
for(Pair<NodeRef, Integer> current : top)
{
System.out.println(""+nodeService.getPaths(current.getFirst(), true) + " "+current.getSecond());
}
top = categoryService.getTopCategories(rootNodeRef.getStoreRef(), QName.createQName(TEST_NAMESPACE, "InvestmentRegion"), 10);
for(Pair<NodeRef, Integer> current : top)
{
System.out.println(""+nodeService.getPaths(current.getFirst(), true) + " "+current.getSecond());
}
top = categoryService.getTopCategories(rootNodeRef.getStoreRef(), QName.createQName(TEST_NAMESPACE, "MarketingRegion"), 10);
for(Pair<NodeRef, Integer> current : top)
{
System.out.println(""+nodeService.getPaths(current.getFirst(), true) + " "+current.getSecond());
}
top = categoryService.getTopCategories(rootNodeRef.getStoreRef(), QName.createQName(TEST_NAMESPACE, "Region"), 10);
for(Pair<NodeRef, Integer> current : top)
{
System.out.println(""+nodeService.getPaths(current.getFirst(), true) + " "+current.getSecond());
}
tx.commit();
}
@SuppressWarnings("unused") @SuppressWarnings("unused")
private int getTotalScore(ResultSet results) private int getTotalScore(ResultSet results)
{ {

View File

@@ -27,8 +27,10 @@ package org.alfresco.repo.search.impl.lucene;
import java.io.IOException; import java.io.IOException;
import java.io.Serializable; import java.io.Serializable;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.ListIterator; import java.util.ListIterator;
import java.util.Map; import java.util.Map;
@@ -60,11 +62,13 @@ import org.alfresco.service.cmr.search.SearchService;
import org.alfresco.service.namespace.NamespacePrefixResolver; import org.alfresco.service.namespace.NamespacePrefixResolver;
import org.alfresco.service.namespace.QName; import org.alfresco.service.namespace.QName;
import org.alfresco.util.ISO9075; import org.alfresco.util.ISO9075;
import org.alfresco.util.Pair;
import org.alfresco.util.SearchLanguageConversion; import org.alfresco.util.SearchLanguageConversion;
import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory; import org.apache.commons.logging.LogFactory;
import org.apache.lucene.index.IndexReader; import org.apache.lucene.index.IndexReader;
import org.apache.lucene.index.Term; import org.apache.lucene.index.Term;
import org.apache.lucene.index.TermDocs;
import org.apache.lucene.index.TermEnum; import org.apache.lucene.index.TermEnum;
import org.apache.lucene.search.Hits; import org.apache.lucene.search.Hits;
import org.apache.lucene.search.Query; import org.apache.lucene.search.Query;
@@ -93,7 +97,7 @@ public class ADMLuceneSearcherImpl extends AbstractLuceneBase implements LuceneS
private NamespacePrefixResolver namespacePrefixResolver; private NamespacePrefixResolver namespacePrefixResolver;
private NodeService nodeService; private NodeService nodeService;
private TenantService tenantService; private TenantService tenantService;
private QueryRegisterComponent queryRegister; private QueryRegisterComponent queryRegister;
@@ -156,13 +160,12 @@ public class ADMLuceneSearcherImpl extends AbstractLuceneBase implements LuceneS
{ {
this.nodeService = nodeService; this.nodeService = nodeService;
} }
public void setTenantService(TenantService tenantService) public void setTenantService(TenantService tenantService)
{ {
this.tenantService = tenantService; this.tenantService = tenantService;
} }
/** /**
* Set the query register * Set the query register
* *
@@ -175,8 +178,8 @@ public class ADMLuceneSearcherImpl extends AbstractLuceneBase implements LuceneS
public ResultSet query(StoreRef store, String language, String queryString, Path[] queryOptions, QueryParameterDefinition[] queryParameterDefinitions) throws SearcherException public ResultSet query(StoreRef store, String language, String queryString, Path[] queryOptions, QueryParameterDefinition[] queryParameterDefinitions) throws SearcherException
{ {
store = tenantService.getName(store); store = tenantService.getName(store);
SearchParameters sp = new SearchParameters(); SearchParameters sp = new SearchParameters();
sp.addStore(store); sp.addStore(store);
sp.setLanguage(language); sp.setLanguage(language);
@@ -206,9 +209,9 @@ public class ADMLuceneSearcherImpl extends AbstractLuceneBase implements LuceneS
{ {
throw new IllegalStateException("Only one store can be searched at present"); throw new IllegalStateException("Only one store can be searched at present");
} }
ArrayList<StoreRef> stores = searchParameters.getStores(); ArrayList<StoreRef> stores = searchParameters.getStores();
stores.set(0, tenantService.getName(searchParameters.getStores().get(0))); stores.set(0, tenantService.getName(searchParameters.getStores().get(0)));
String parameterisedQueryString; String parameterisedQueryString;
if (searchParameters.getQueryParameterDefinitions().size() > 0) if (searchParameters.getQueryParameterDefinitions().size() > 0)
@@ -243,18 +246,9 @@ public class ADMLuceneSearcherImpl extends AbstractLuceneBase implements LuceneS
} }
ClosingIndexSearcher searcher = getSearcher(indexer); ClosingIndexSearcher searcher = getSearcher(indexer);
Query query = LuceneQueryParser.parse( Query query = LuceneQueryParser.parse(parameterisedQueryString, DEFAULT_FIELD, new LuceneAnalyser(getDictionaryService(),
parameterisedQueryString, DEFAULT_FIELD, searchParameters.getMlAnalaysisMode() == null ? getLuceneConfig().getDefaultMLSearchAnalysisMode() : searchParameters.getMlAnalaysisMode()),
new LuceneAnalyser( namespacePrefixResolver, getDictionaryService(), tenantService, defaultOperator, searchParameters, getLuceneConfig(), searcher.getIndexReader());
getDictionaryService(),
searchParameters.getMlAnalaysisMode() == null ? getLuceneConfig().getDefaultMLSearchAnalysisMode() : searchParameters.getMlAnalaysisMode()),
namespacePrefixResolver,
getDictionaryService(),
tenantService,
defaultOperator,
searchParameters,
getLuceneConfig(),
searcher.getIndexReader());
if (s_logger.isDebugEnabled()) if (s_logger.isDebugEnabled())
{ {
s_logger.debug("Query is " + query.toString()); s_logger.debug("Query is " + query.toString());
@@ -277,24 +271,24 @@ public class ADMLuceneSearcherImpl extends AbstractLuceneBase implements LuceneS
{ {
case FIELD: case FIELD:
String field = sd.getField(); String field = sd.getField();
if(field.startsWith("@")) if (field.startsWith("@"))
{ {
field = expandAttributeFieldName(field); field = expandAttributeFieldName(field);
PropertyDefinition propertyDef = getDictionaryService().getProperty(QName.createQName(field.substring(1))); PropertyDefinition propertyDef = getDictionaryService().getProperty(QName.createQName(field.substring(1)));
if (propertyDef.getDataType().getName().equals(DataTypeDefinition.DATETIME)) if (propertyDef.getDataType().getName().equals(DataTypeDefinition.DATETIME))
{ {
DataTypeDefinition dataType = propertyDef.getDataType(); DataTypeDefinition dataType = propertyDef.getDataType();
String analyserClassName = dataType.getAnalyserClassName(); String analyserClassName = dataType.getAnalyserClassName();
if(analyserClassName.equals(DateTimeAnalyser.class.getCanonicalName())) if (analyserClassName.equals(DateTimeAnalyser.class.getCanonicalName()))
{ {
field = field + ".sort"; field = field + ".sort";
} }
} }
} }
if (fieldHasTerm(searcher.getReader(), field)) if (fieldHasTerm(searcher.getReader(), field))
{ {
fields[index++] = new SortField(field, !sd.isAscending()); fields[index++] = new SortField(field, !sd.isAscending());
} }
else else
@@ -319,13 +313,7 @@ public class ADMLuceneSearcherImpl extends AbstractLuceneBase implements LuceneS
} }
Path[] paths = searchParameters.getAttributePaths().toArray(new Path[0]); Path[] paths = searchParameters.getAttributePaths().toArray(new Path[0]);
return new LuceneResultSet( return new LuceneResultSet(hits, searcher, nodeService, tenantService, paths, searchParameters);
hits,
searcher,
nodeService,
tenantService,
paths,
searchParameters);
} }
catch (ParseException e) catch (ParseException e)
{ {
@@ -358,13 +346,7 @@ public class ADMLuceneSearcherImpl extends AbstractLuceneBase implements LuceneS
return new EmptyResultSet(); return new EmptyResultSet();
} }
Hits hits = searcher.search(query); Hits hits = searcher.search(query);
return new LuceneResultSet( return new LuceneResultSet(hits, searcher, nodeService, tenantService, searchParameters.getAttributePaths().toArray(new Path[0]), searchParameters);
hits,
searcher,
nodeService,
tenantService,
searchParameters.getAttributePaths().toArray(new Path[0]),
searchParameters);
} }
catch (SAXPathException e) catch (SAXPathException e)
{ {
@@ -584,9 +566,9 @@ public class ADMLuceneSearcherImpl extends AbstractLuceneBase implements LuceneS
boolean followAllParentLinks, String language) throws InvalidNodeRefException, XPathException boolean followAllParentLinks, String language) throws InvalidNodeRefException, XPathException
{ {
NodeSearcher nodeSearcher = new NodeSearcher(nodeService, getDictionaryService(), this); NodeSearcher nodeSearcher = new NodeSearcher(nodeService, getDictionaryService(), this);
contextNodeRef = tenantService.getName(contextNodeRef); contextNodeRef = tenantService.getName(contextNodeRef);
return nodeSearcher.selectNodes(contextNodeRef, xpath, parameters, namespacePrefixResolver, followAllParentLinks, language); return nodeSearcher.selectNodes(contextNodeRef, xpath, parameters, namespacePrefixResolver, followAllParentLinks, language);
} }
@@ -750,4 +732,91 @@ public class ADMLuceneSearcherImpl extends AbstractLuceneBase implements LuceneS
} }
return fieldName; return fieldName;
} }
public List<Pair<String, Integer>> getTopTerms(String field, int count)
{
ClosingIndexSearcher searcher = null;
try
{
LinkedList<Pair<String, Integer>> answer = new LinkedList<Pair<String, Integer>>();
searcher = getSearcher(indexer);
IndexReader reader = searcher.getIndexReader();
TermEnum terms = reader.terms(new Term(field, ""));
while (terms.next())
{
Term term = terms.term();
if(!term.field().equals(field))
{
break;
}
int freq = terms.docFreq();
Pair<String, Integer> pair = new Pair<String, Integer>(term.text(), Integer.valueOf(freq));
if (answer.size() < count)
{
if (answer.size() == 0)
{
answer.add(pair);
}
else if (answer.get(answer.size() - 1).getSecond().compareTo(pair.getSecond()) >= 0)
{
answer.add(pair);
}
else
{
for (ListIterator<Pair<String, Integer>> it = answer.listIterator(); it.hasNext(); /**/)
{
Pair<String, Integer> test = it.next();
if (test.getSecond().compareTo(pair.getSecond()) < 0)
{
it.previous();
it.add(pair);
break;
}
}
}
}
else if (answer.get(count - 1).getSecond().compareTo(pair.getSecond()) < 0)
{
for (ListIterator<Pair<String, Integer>> it = answer.listIterator(); it.hasNext(); /**/)
{
Pair<String, Integer> test = it.next();
if (test.getSecond().compareTo(pair.getSecond()) < 0)
{
it.previous();
it.add(pair);
break;
}
}
answer.removeLast();
}
else
{
// off the end
}
}
terms.close();
return answer;
}
catch (IOException e)
{
throw new SearcherException(e);
}
finally
{
if (searcher != null)
{
try
{
searcher.close();
}
catch (IOException e)
{
throw new SearcherException(e);
}
}
}
}
} }

View File

@@ -31,6 +31,7 @@ import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.Set; import java.util.Set;
import org.alfresco.error.AlfrescoRuntimeException; import org.alfresco.error.AlfrescoRuntimeException;
@@ -38,7 +39,10 @@ import org.alfresco.model.ContentModel;
import org.alfresco.repo.search.IndexerAndSearcher; import org.alfresco.repo.search.IndexerAndSearcher;
import org.alfresco.repo.search.IndexerException; import org.alfresco.repo.search.IndexerException;
import org.alfresco.repo.tenant.TenantService; import org.alfresco.repo.tenant.TenantService;
import org.alfresco.service.cmr.dictionary.AspectDefinition;
import org.alfresco.service.cmr.dictionary.DataTypeDefinition;
import org.alfresco.service.cmr.dictionary.DictionaryService; import org.alfresco.service.cmr.dictionary.DictionaryService;
import org.alfresco.service.cmr.dictionary.PropertyDefinition;
import org.alfresco.service.cmr.repository.ChildAssociationRef; import org.alfresco.service.cmr.repository.ChildAssociationRef;
import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService; import org.alfresco.service.cmr.repository.NodeService;
@@ -47,22 +51,25 @@ import org.alfresco.service.cmr.repository.StoreRef;
import org.alfresco.service.cmr.search.CategoryService; import org.alfresco.service.cmr.search.CategoryService;
import org.alfresco.service.cmr.search.ResultSet; import org.alfresco.service.cmr.search.ResultSet;
import org.alfresco.service.cmr.search.ResultSetRow; import org.alfresco.service.cmr.search.ResultSetRow;
import org.alfresco.service.cmr.search.SearchService;
import org.alfresco.service.namespace.NamespacePrefixResolver; import org.alfresco.service.namespace.NamespacePrefixResolver;
import org.alfresco.service.namespace.QName; import org.alfresco.service.namespace.QName;
import org.alfresco.util.ISO9075; import org.alfresco.util.ISO9075;
import org.alfresco.util.Pair;
/** /**
* Category service implementation * Category service implementation
* *
* @author andyh * @author andyh
*
*/ */
public class LuceneCategoryServiceImpl implements CategoryService public class LuceneCategoryServiceImpl implements CategoryService
{ {
private NodeService nodeService; private NodeService nodeService;
private NodeService publicNodeService;
private TenantService tenantService; private TenantService tenantService;
private NamespacePrefixResolver namespacePrefixResolver; private NamespacePrefixResolver namespacePrefixResolver;
private DictionaryService dictionaryService; private DictionaryService dictionaryService;
@@ -81,6 +88,7 @@ public class LuceneCategoryServiceImpl implements CategoryService
/** /**
* Set the node service * Set the node service
*
* @param nodeService * @param nodeService
*/ */
public void setNodeService(NodeService nodeService) public void setNodeService(NodeService nodeService)
@@ -88,8 +96,19 @@ public class LuceneCategoryServiceImpl implements CategoryService
this.nodeService = nodeService; this.nodeService = nodeService;
} }
/**
* Set the public node service
*
* @param nodeService
*/
public void setPublicNodeService(NodeService publicNodeService)
{
this.publicNodeService = publicNodeService;
}
/** /**
* Set the tenant service * Set the tenant service
*
* @param tenantService * @param tenantService
*/ */
public void setTenantService(TenantService tenantService) public void setTenantService(TenantService tenantService)
@@ -99,6 +118,7 @@ public class LuceneCategoryServiceImpl implements CategoryService
/** /**
* Set the service to map prefixes to uris * Set the service to map prefixes to uris
*
* @param namespacePrefixResolver * @param namespacePrefixResolver
*/ */
public void setNamespacePrefixResolver(NamespacePrefixResolver namespacePrefixResolver) public void setNamespacePrefixResolver(NamespacePrefixResolver namespacePrefixResolver)
@@ -108,6 +128,7 @@ public class LuceneCategoryServiceImpl implements CategoryService
/** /**
* Set the dictionary service * Set the dictionary service
*
* @param dictionaryService * @param dictionaryService
*/ */
public void setDictionaryService(DictionaryService dictionaryService) public void setDictionaryService(DictionaryService dictionaryService)
@@ -117,6 +138,7 @@ public class LuceneCategoryServiceImpl implements CategoryService
/** /**
* Set the indexer and searcher * Set the indexer and searcher
*
* @param indexerAndSearcher * @param indexerAndSearcher
*/ */
public void setIndexerAndSearcher(IndexerAndSearcher indexerAndSearcher) public void setIndexerAndSearcher(IndexerAndSearcher indexerAndSearcher)
@@ -132,13 +154,13 @@ public class LuceneCategoryServiceImpl implements CategoryService
} }
categoryRef = tenantService.getName(categoryRef); categoryRef = tenantService.getName(categoryRef);
ResultSet resultSet = null; ResultSet resultSet = null;
try try
{ {
StringBuilder luceneQuery = new StringBuilder(64); StringBuilder luceneQuery = new StringBuilder(64);
switch(mode) switch (mode)
{ {
case ALL: case ALL:
luceneQuery.append("PATH:\""); luceneQuery.append("PATH:\"");
@@ -264,15 +286,15 @@ public class LuceneCategoryServiceImpl implements CategoryService
ResultSet resultSet = null; ResultSet resultSet = null;
try try
{ {
resultSet = indexerAndSearcher.getSearcher(storeRef, false).query(storeRef, "lucene", "PATH:\"/" + getPrefix(qname.getNamespaceURI()) + ISO9075.encode(qname.getLocalName()) + "\"", resultSet = indexerAndSearcher.getSearcher(storeRef, false).query(storeRef, "lucene",
null, null); "PATH:\"/" + getPrefix(qname.getNamespaceURI()) + ISO9075.encode(qname.getLocalName()) + "\"", null, null);
Set<NodeRef> nodeRefs = new HashSet<NodeRef>(resultSet.length()); Set<NodeRef> nodeRefs = new HashSet<NodeRef>(resultSet.length());
for (ResultSetRow row : resultSet) for (ResultSetRow row : resultSet)
{ {
nodeRefs.add(row.getNodeRef()); nodeRefs.add(row.getNodeRef());
} }
return nodeRefs; return nodeRefs;
} }
finally finally
@@ -305,7 +327,7 @@ public class LuceneCategoryServiceImpl implements CategoryService
public Collection<QName> getClassificationAspects() public Collection<QName> getClassificationAspects()
{ {
return dictionaryService.getSubAspects(ContentModel.ASPECT_CLASSIFIABLE, true); return dictionaryService.getSubAspects(ContentModel.ASPECT_CLASSIFIABLE, true);
} }
public NodeRef createClassifiction(StoreRef storeRef, QName typeName, String attributeName) public NodeRef createClassifiction(StoreRef storeRef, QName typeName, String attributeName)
@@ -326,23 +348,23 @@ public class LuceneCategoryServiceImpl implements CategoryService
public NodeRef createCategory(NodeRef parent, String name) public NodeRef createCategory(NodeRef parent, String name)
{ {
if(!nodeService.exists(parent)) if (!nodeService.exists(parent))
{ {
throw new AlfrescoRuntimeException("Missing category?"); throw new AlfrescoRuntimeException("Missing category?");
} }
String uri = nodeService.getPrimaryParent(parent).getQName().getNamespaceURI(); String uri = nodeService.getPrimaryParent(parent).getQName().getNamespaceURI();
String validLocalName = QName.createValidLocalName(name); String validLocalName = QName.createValidLocalName(name);
NodeRef newCategory = nodeService.createNode(parent, ContentModel.ASSOC_SUBCATEGORIES, QName.createQName(uri, validLocalName), ContentModel.TYPE_CATEGORY).getChildRef(); NodeRef newCategory = publicNodeService.createNode(parent, ContentModel.ASSOC_SUBCATEGORIES, QName.createQName(uri, validLocalName), ContentModel.TYPE_CATEGORY).getChildRef();
nodeService.setProperty(newCategory, ContentModel.PROP_NAME, name); publicNodeService.setProperty(newCategory, ContentModel.PROP_NAME, name);
return newCategory; return newCategory;
} }
public NodeRef createRootCategory(StoreRef storeRef, QName aspectName, String name) public NodeRef createRootCategory(StoreRef storeRef, QName aspectName, String name)
{ {
Set<NodeRef> nodeRefs = getClassificationNodes(storeRef, aspectName); Set<NodeRef> nodeRefs = getClassificationNodes(storeRef, aspectName);
if(nodeRefs.size() == 0) if (nodeRefs.size() == 0)
{ {
throw new AlfrescoRuntimeException("Missing classification: "+aspectName); throw new AlfrescoRuntimeException("Missing classification: " + aspectName);
} }
NodeRef parent = nodeRefs.iterator().next(); NodeRef parent = nodeRefs.iterator().next();
return createCategory(parent, name); return createCategory(parent, name);
@@ -350,16 +372,78 @@ public class LuceneCategoryServiceImpl implements CategoryService
public void deleteCategory(NodeRef nodeRef) public void deleteCategory(NodeRef nodeRef)
{ {
nodeService.deleteNode(nodeRef); publicNodeService.deleteNode(nodeRef);
} }
public void deleteClassification(StoreRef storeRef, QName aspectName) public void deleteClassification(StoreRef storeRef, QName aspectName)
{ {
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();
} }
public List<Pair<NodeRef, Integer>> getTopCategories(StoreRef storeRef, QName aspectName, int count)
{
if (indexerAndSearcher instanceof LuceneIndexerAndSearcher)
{
AspectDefinition definition = dictionaryService.getAspect(aspectName);
if(definition == null)
{
throw new IllegalStateException("Unknown aspect");
}
QName catProperty = null;
Map<QName, PropertyDefinition> properties = definition.getProperties();
for(QName pName : properties.keySet())
{
if(pName.getNamespaceURI().equals(aspectName.getNamespaceURI()))
{
if(pName.getLocalName().equalsIgnoreCase(aspectName.getLocalName()))
{
PropertyDefinition def = properties.get(pName);
if(def.getDataType().getName().equals(DataTypeDefinition.CATEGORY))
{
catProperty = pName;
}
}
}
}
if(catProperty == null)
{
throw new IllegalStateException("Aspect does not have category property mirroring the aspect name");
}
LuceneIndexerAndSearcher lias = (LuceneIndexerAndSearcher) indexerAndSearcher;
String field = "@" + catProperty;
SearchService searchService = lias.getSearcher(storeRef, true);
if (searchService instanceof LuceneSearcher)
{
LuceneSearcher luceneSearcher = (LuceneSearcher)searchService;
List<Pair<String, Integer>> topTerms = luceneSearcher.getTopTerms(field, count);
List<Pair<NodeRef, Integer>> answer = new ArrayList<Pair<NodeRef, Integer>>();
for (Pair<String, Integer> term : topTerms)
{
Pair<NodeRef, Integer> toAdd;
NodeRef nodeRef = new NodeRef(term.getFirst());
if (nodeService.exists(nodeRef))
{
toAdd = new Pair<NodeRef, Integer>(nodeRef, term.getSecond());
}
else
{
toAdd = new Pair<NodeRef, Integer>(null, term.getSecond());
}
answer.add(toAdd);
}
return answer;
}
else
{
throw new UnsupportedOperationException("getPolularCategories is only supported for lucene indexes");
}
}
else
{
throw new UnsupportedOperationException("getPolularCategories is only supported for lucene indexes");
}
}
} }

View File

@@ -24,8 +24,13 @@
*/ */
package org.alfresco.repo.search.impl.lucene; package org.alfresco.repo.search.impl.lucene;
import java.util.List;
import org.alfresco.repo.search.IndexerAndSearcher; import org.alfresco.repo.search.IndexerAndSearcher;
import org.alfresco.repo.search.IndexerException; import org.alfresco.repo.search.IndexerException;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.StoreRef;
import org.alfresco.util.Pair;
public interface LuceneIndexerAndSearcher extends IndexerAndSearcher, LuceneConfig public interface LuceneIndexerAndSearcher extends IndexerAndSearcher, LuceneConfig
{ {
@@ -40,4 +45,5 @@ public interface LuceneIndexerAndSearcher extends IndexerAndSearcher, LuceneConf
} }
public <R> R doWithAllWriteLocks(WithAllWriteLocksWork<R> lockWork); public <R> R doWithAllWriteLocks(WithAllWriteLocksWork<R> lockWork);
} }

View File

@@ -24,9 +24,13 @@
*/ */
package org.alfresco.repo.search.impl.lucene; package org.alfresco.repo.search.impl.lucene;
import java.util.List;
import org.alfresco.service.cmr.repository.NodeService; import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.repository.StoreRef;
import org.alfresco.service.cmr.search.SearchService; import org.alfresco.service.cmr.search.SearchService;
import org.alfresco.service.namespace.NamespacePrefixResolver; import org.alfresco.service.namespace.NamespacePrefixResolver;
import org.alfresco.util.Pair;
/** /**
* Lucene implementation specific entension to the seracher API * Lucene implementation specific entension to the seracher API
@@ -50,4 +54,13 @@ public interface LuceneSearcher extends SearchService
* @param namespacePrefixResolver * @param namespacePrefixResolver
*/ */
public void setNamespacePrefixResolver(NamespacePrefixResolver namespacePrefixResolver); public void setNamespacePrefixResolver(NamespacePrefixResolver namespacePrefixResolver);
/**
* Get top terms
*
* @param field
* @param count
* @return
*/
public List<Pair<String, Integer>> getTopTerms(String field, int count);
} }

View File

@@ -25,6 +25,7 @@
package org.alfresco.service.cmr.search; package org.alfresco.service.cmr.search;
import java.util.Collection; import java.util.Collection;
import java.util.List;
import org.alfresco.service.Auditable; import org.alfresco.service.Auditable;
import org.alfresco.service.PublicService; import org.alfresco.service.PublicService;
@@ -32,6 +33,7 @@ import org.alfresco.service.cmr.repository.ChildAssociationRef;
import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.StoreRef; import org.alfresco.service.cmr.repository.StoreRef;
import org.alfresco.service.namespace.QName; import org.alfresco.service.namespace.QName;
import org.alfresco.util.Pair;
/** /**
* Category Service * Category Service
@@ -163,4 +165,14 @@ public interface CategoryService
*/ */
@Auditable(key = Auditable.Key.ARG_0, parameters = {"nodeRef"}) @Auditable(key = Auditable.Key.ARG_0, parameters = {"nodeRef"})
public void deleteCategory(NodeRef nodeRef); public void deleteCategory(NodeRef nodeRef);
/**
* Get the most polular categories
*
* @param storeRef
* @param aspectName
* @param count
* @return
*/
public List<Pair<NodeRef, Integer>> getTopCategories(StoreRef storeRef, QName aspectName, int count);
} }