SLNG-8110: Add post query sort for datetime it required (default field in the index only sorts to date)

git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@9971 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
Andrew Hind 2008-07-22 11:34:31 +00:00
parent cef534a8c1
commit ec903f2dc1
6 changed files with 438 additions and 5 deletions

View File

@ -29,6 +29,7 @@ import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import org.alfresco.service.cmr.repository.ChildAssociationRef;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.Path;
import org.alfresco.service.cmr.search.ResultSet;
@ -77,6 +78,16 @@ public abstract class AbstractResultSetRow implements ResultSetRow
return getResultSet().getNodeRef(getIndex());
}
public QName getQName()
{
return getResultSet().getChildAssocRef(getIndex()).getQName();
}
public ChildAssociationRef getChildAssocRef()
{
return getResultSet().getChildAssocRef(getIndex());
}
public float getScore()
{
return getResultSet().getScore(getIndex());
@ -92,6 +103,11 @@ public abstract class AbstractResultSetRow implements ResultSetRow
return Collections.unmodifiableMap(properties);
}
public Serializable getValue(Path path)
{
return properties.get(path);
}
protected Map<QName, Serializable> getDirectProperties()
{
return Collections.<QName, Serializable>emptyMap();

View File

@ -44,6 +44,7 @@ import org.alfresco.repo.search.impl.NodeSearcher;
import org.alfresco.repo.search.impl.lucene.QueryParser.Operator;
import org.alfresco.repo.tenant.TenantService;
import org.alfresco.repo.search.impl.lucene.analysis.DateTimeAnalyser;
import org.alfresco.repo.search.results.SortedResultSet;
import org.alfresco.service.cmr.dictionary.DataTypeDefinition;
import org.alfresco.service.cmr.dictionary.DictionaryService;
import org.alfresco.service.cmr.dictionary.PropertyDefinition;
@ -261,6 +262,7 @@ public class ADMLuceneSearcherImpl extends AbstractLuceneBase implements LuceneS
Hits hits;
boolean requiresPostSort = false;
if (searchParameters.getSortDefinitions().size() > 0)
{
int index = 0;
@ -284,6 +286,10 @@ public class ADMLuceneSearcherImpl extends AbstractLuceneBase implements LuceneS
{
field = field + ".sort";
}
else
{
requiresPostSort = true;
}
}
}
@ -306,6 +312,7 @@ public class ADMLuceneSearcherImpl extends AbstractLuceneBase implements LuceneS
}
hits = searcher.search(query, new Sort(fields));
}
else
{
@ -313,7 +320,16 @@ public class ADMLuceneSearcherImpl extends AbstractLuceneBase implements LuceneS
}
Path[] paths = searchParameters.getAttributePaths().toArray(new Path[0]);
return new LuceneResultSet(hits, searcher, nodeService, tenantService, paths, searchParameters);
ResultSet rs = new LuceneResultSet(hits, searcher, nodeService, tenantService, paths, searchParameters);
if(requiresPostSort)
{
ResultSet sorted = new SortedResultSet(rs, nodeService, searchParameters, namespacePrefixResolver);
return sorted;
}
else
{
return rs;
}
}
catch (ParseException e)
{

View File

@ -409,8 +409,12 @@ public class ADMLuceneTest extends TestCase
nodeService.addChild(n12, n14, ASSOC_TYPE_QNAME, QName.createQName("{namespace}common"));
nodeService.addChild(n13, n14, ASSOC_TYPE_QNAME, QName.createQName("{namespace}common"));
documentOrder = new NodeRef[] { rootNodeRef, n1, n2, n3, n4, n5, n6, n7, n8, n9, n10, n11, n12, n13, n14 };
documentOrder = new NodeRef[] { rootNodeRef, n4, n5, n6, n7, n8, n9, n10, n11, n12, n13, n14, n3, n1, n2 };
nodeService.addAspect(n3, ContentModel.ASPECT_AUDITABLE, null);
nodeService.addAspect(n1, ContentModel.ASPECT_AUDITABLE, null);
nodeService.setProperty(n1, ContentModel.PROP_MODIFIED, new Date(new Date().getTime() - 1000*60*60));
nodeService.addAspect(n2, ContentModel.ASPECT_AUDITABLE, null);
}
private double orderDoubleCount = -0.11d;
@ -1617,7 +1621,7 @@ public class ADMLuceneTest extends TestCase
date = currentBun;
}
results.close();
SearchParameters sp_7 = new SearchParameters();
sp_7.addStore(rootNodeRef.getStoreRef());
sp_7.setLanguage(SearchService.LANGUAGE_LUCENE);
@ -1629,7 +1633,7 @@ public class ADMLuceneTest extends TestCase
for (ResultSetRow row : results)
{
Date currentBun = DefaultTypeConverter.INSTANCE.convert(Date.class, nodeService.getProperty(row.getNodeRef(), ContentModel.PROP_MODIFIED));
// System.out.println(currentBun);
//System.out.println("A " + currentBun + " "+row.getQName());
if (date != null)
{
assertTrue(date.compareTo(currentBun) <= 0);
@ -1835,7 +1839,7 @@ public class ADMLuceneTest extends TestCase
sp17.addSort("cabbage", false);
results = searcher.query(sp17);
results.close();
luceneFTS.resume();
}
@ -2155,6 +2159,9 @@ public class ADMLuceneTest extends TestCase
indexer.createNode(new ChildAssociationRef(ASSOC_TYPE_QNAME, n5, QName.createQName("{namespace}twelve"), n12));
indexer.createNode(new ChildAssociationRef(ASSOC_TYPE_QNAME, n12, QName.createQName("{namespace}thirteen"), n13));
indexer.createNode(new ChildAssociationRef(ASSOC_TYPE_QNAME, n13, QName.createQName("{namespace}fourteen"), n14));
indexer.updateNode(n3);
indexer.updateNode(n1);
indexer.updateNode(n2);
indexer.prepare();
indexer.commit();
}

View File

@ -0,0 +1,284 @@
/*
* Copyright (C) 2005-2007 Alfresco Software Limited.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program 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 General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
* As a special exception to the terms and conditions of version 2.0 of
* the GPL, you may redistribute this Program in connection with Free/Libre
* and Open Source Software ("FLOSS") applications as described in Alfresco's
* FLOSS exception. You should have recieved a copy of the text describing
* the FLOSS exception, and it is also available here:
* http://www.alfresco.com/legal/licensing"
*/
package org.alfresco.repo.search.results;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
import org.alfresco.repo.search.SearcherException;
import org.alfresco.repo.search.impl.lucene.LuceneResultSetRow;
import org.alfresco.repo.search.impl.lucene.analysis.DateTimeAnalyser;
import org.alfresco.service.cmr.dictionary.DataTypeDefinition;
import org.alfresco.service.cmr.dictionary.PropertyDefinition;
import org.alfresco.service.cmr.repository.ChildAssociationRef;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.repository.Path;
import org.alfresco.service.cmr.search.ResultSet;
import org.alfresco.service.cmr.search.ResultSetMetaData;
import org.alfresco.service.cmr.search.ResultSetRow;
import org.alfresco.service.cmr.search.SearchParameters;
import org.alfresco.service.cmr.search.SearchParameters.SortDefinition;
import org.alfresco.service.namespace.NamespacePrefixResolver;
import org.alfresco.service.namespace.NamespaceService;
import org.alfresco.service.namespace.QName;
import org.apache.lucene.search.SortField;
public class SortedResultSet implements ResultSet
{
ArrayList<NodeRefAndScore> nodeRefsAndScores;
NodeService nodeService;
SearchParameters searchParameters;
ResultSet resultSet;
public SortedResultSet(ResultSet resultSet, NodeService nodeService, SearchParameters searchParameters, NamespacePrefixResolver namespacePrefixResolver)
{
this.nodeService = nodeService;
this.searchParameters = searchParameters;
this.resultSet = resultSet;
nodeRefsAndScores = new ArrayList<NodeRefAndScore>(resultSet.length());
for (ResultSetRow row : resultSet)
{
nodeRefsAndScores.add(new NodeRefAndScore(row.getNodeRef(), row.getScore()));
}
ArrayList<AttributeOrder> order = new ArrayList<AttributeOrder>();
for (SortDefinition sd : searchParameters.getSortDefinitions())
{
switch (sd.getSortType())
{
case FIELD:
String field = sd.getField();
if (field.startsWith("@"))
{
QName qname = expandAttributeFieldName(field, namespacePrefixResolver);
order.add(new AttributeOrder(qname, sd.isAscending()));
}
break;
case DOCUMENT:
// ignore
break;
case SCORE:
// ignore
break;
}
}
orderNodes(nodeRefsAndScores, order);
}
public void close()
{
resultSet.close();
}
public ChildAssociationRef getChildAssocRef(int n)
{
return nodeService.getPrimaryParent(nodeRefsAndScores.get(n).nodeRef);
}
public List<NodeRef> getNodeRefs()
{
ArrayList<NodeRef> nodeRefs = new ArrayList<NodeRef>(length());
for (ResultSetRow row : this)
{
nodeRefs.add(row.getNodeRef());
}
return nodeRefs;
}
public List<ChildAssociationRef> getChildAssocRefs()
{
ArrayList<ChildAssociationRef> cars = new ArrayList<ChildAssociationRef>(length());
for (ResultSetRow row : this)
{
cars.add(row.getChildAssocRef());
}
return cars;
}
public NodeRef getNodeRef(int n)
{
return nodeRefsAndScores.get(n).nodeRef;
}
public Path[] getPropertyPaths()
{
return resultSet.getPropertyPaths();
}
public ResultSetMetaData getResultSetMetaData()
{
return resultSet.getResultSetMetaData();
}
public ResultSetRow getRow(int i)
{
if (i < length())
{
return new SortedResultSetRow(this, i);
}
else
{
throw new SearcherException("Invalid row");
}
}
public float getScore(int n)
{
return nodeRefsAndScores.get(n).score;
}
public int length()
{
return nodeRefsAndScores.size();
}
public Iterator<ResultSetRow> iterator()
{
return new SortedResultSetRowIterator(this);
}
private void orderNodes(List<NodeRefAndScore> answer, List<AttributeOrder> order)
{
Collections.sort(answer, new NodeRefAndScoreComparator(nodeService, order));
}
private QName expandAttributeFieldName(String field, NamespacePrefixResolver namespacePrefixResolver)
{
QName qname;
// Check for any prefixes and expand to the full uri
if (field.charAt(1) != '{')
{
int colonPosition = field.indexOf(':');
if (colonPosition == -1)
{
// use the default namespace
qname = QName.createQName(NamespaceService.DEFAULT_URI, field.substring(1));
}
else
{
// find the prefix
qname = QName.createQName(field.substring(1, colonPosition), field.substring(colonPosition + 1), namespacePrefixResolver);
}
}
else
{
qname = QName.createQName(field.substring(1));
}
return qname;
}
static class NodeRefAndScoreComparator implements Comparator<NodeRefAndScore>
{
List<AttributeOrder> order;
NodeService nodeService;
NodeRefAndScoreComparator(NodeService nodeService, List<AttributeOrder> order)
{
this.nodeService = nodeService;
this.order = order;
}
@SuppressWarnings("unchecked")
public int compare(NodeRefAndScore n1, NodeRefAndScore n2)
{
for (AttributeOrder attributeOrder : order)
{
Serializable o1 = nodeService.getProperty(n1.nodeRef, attributeOrder.attribute);
Serializable o2 = nodeService.getProperty(n2.nodeRef, attributeOrder.attribute);
if (o1 == null)
{
if (o2 == null)
{
continue;
}
else
{
return attributeOrder.ascending ? -1 : 1;
}
}
else
{
if (o2 == null)
{
return attributeOrder.ascending ? 1 : -1;
}
else
{
if ((o1 instanceof Comparable) && (o2 instanceof Comparable))
{
return (attributeOrder.ascending ? 1 : -1) * ((Comparable) o1).compareTo((Comparable) o2);
}
else
{
continue;
}
}
}
}
return 0;
}
}
private static class AttributeOrder
{
QName attribute;
boolean ascending;
AttributeOrder(QName attribute, boolean ascending)
{
this.attribute = attribute;
this.ascending = ascending;
}
}
private static class NodeRefAndScore
{
NodeRef nodeRef;
float score;
NodeRefAndScore(NodeRef nodeRef, float score)
{
this.nodeRef = nodeRef;
this.score = score;
}
}
}

View File

@ -0,0 +1,52 @@
/*
* Copyright (C) 2005-2007 Alfresco Software Limited.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program 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 General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
* As a special exception to the terms and conditions of version 2.0 of
* the GPL, you may redistribute this Program in connection with Free/Libre
* and Open Source Software ("FLOSS") applications as described in Alfresco's
* FLOSS exception. You should have recieved a copy of the text describing
* the FLOSS exception, and it is also available here:
* http://www.alfresco.com/legal/licensing"
*/
package org.alfresco.repo.search.results;
import org.alfresco.repo.search.AbstractResultSetRow;
import org.alfresco.service.cmr.search.ResultSetRow;
/**
* @author andyh
*
*/
public class SortedResultSetRow extends AbstractResultSetRow implements ResultSetRow
{
/**
* @param resultSet
* @param index
*/
public SortedResultSetRow(SortedResultSet resultSet, int index)
{
super(resultSet, index);
}
}

View File

@ -0,0 +1,58 @@
/*
* Copyright (C) 2005-2007 Alfresco Software Limited.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program 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 General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
* As a special exception to the terms and conditions of version 2.0 of
* the GPL, you may redistribute this Program in connection with Free/Libre
* and Open Source Software ("FLOSS") applications as described in Alfresco's
* FLOSS exception. You should have recieved a copy of the text describing
* the FLOSS exception, and it is also available here:
* http://www.alfresco.com/legal/licensing"
*/
package org.alfresco.repo.search.results;
import org.alfresco.repo.search.AbstractResultSetRowIterator;
import org.alfresco.service.cmr.search.ResultSet;
import org.alfresco.service.cmr.search.ResultSetRow;
/**
* @author andyh
*
*/
public class SortedResultSetRowIterator extends AbstractResultSetRowIterator
{
/**
* @param resultSet
*/
public SortedResultSetRowIterator(ResultSet resultSet)
{
super(resultSet);
}
@Override
public ResultSetRow next()
{
return new SortedResultSetRow((SortedResultSet)getResultSet(), moveToNextPosition());
}
@Override
public ResultSetRow previous()
{
return new SortedResultSetRow((SortedResultSet)getResultSet(), moveToPreviousPosition());
}
}