Optimized EntityInstances and ModelingUtils.search*Shallow queries 15/815/1
authorTuukka Lehtonen <tuukka.lehtonen@semantum.fi>
Mon, 7 Aug 2017 15:05:35 +0000 (18:05 +0300)
committerTuukka Lehtonen <tuukka.lehtonen@semantum.fi>
Mon, 7 Aug 2017 15:05:35 +0000 (18:05 +0300)
Shallow queries were previously doing tons of useless queries into
dependent ontologies which would have been filtered out anyway. Also
EntityInstances.QueryIndex.perform now optimizes two corner cases:
* only one search result which is usual for GUID searches
* removal of Types:*Entity filter term which is useless because all
  instances are entities.

refs #7415

Change-Id: I89b9495ea51ca8fba4bd40db113c91f4a12932d0

bundles/org.simantics.db.layer0/src/org/simantics/db/layer0/adapter/impl/EntityInstances.java
bundles/org.simantics.db.procore/src/fi/vtt/simantics/procore/internal/CollectionSupportImpl.java
bundles/org.simantics.db/src/org/simantics/db/service/CollectionSupport.java
bundles/org.simantics.modeling/src/org/simantics/modeling/ModelingUtils.java

index 488545c5fec781c80876b9cf7035f8b0eed31c06..2347fa99e5c0e7331b3fbd12d04f3705371af52e 100644 (file)
@@ -70,58 +70,64 @@ public class EntityInstances implements Instances {
         public List<Resource> perform(ReadGraph graph)
                 throws DatabaseException {
             Resource type = parameter2;
-
-            Layer0 L0 = Layer0.getInstance(graph);
-            Layer0X L0X = Layer0X.getInstance(graph);
-            String typeName = graph.getRelatedValue(type, L0.HasName);
-            if (typeName.isEmpty())
+            String filter = constructLuceneQuery(graph, type, parameter3);
+            if (filter == null)
                 return Collections.emptyList();
 
             @SuppressWarnings({ "unchecked", "rawtypes" })
-            Function dependencyResources = graph.syncRequest(new Adapter(L0X.DependencyResources, Function.class), TransientCacheListener.<Function>instance());
-
-            StringBuilder filtersb = new StringBuilder();
-            filtersb.append("Types:*").append( IndexQueries.escape( typeName, true ) );
-            if (parameter3.length() > 0)
-                filtersb.append(" AND ").append( parameter3 );
-            String filter = filtersb.toString();
+            Function dependencyResources = graph.syncRequest(new Adapter(Layer0X.getInstance(graph).DependencyResources, Function.class), TransientCacheListener.<Function>instance());
 
             if (TRACE_QUERIES) {
                 System.out.println("EntityInstances.QueryIndex: finding " + filter + " from index " + graph.getPossibleURI(parameter));
                 //new Exception("EntityInstances: finding " + filter + " from index " + graph.getPossibleURI(parameter)).printStackTrace();
             }
-            
+
             @SuppressWarnings("unchecked")
-                       List<Resource> results = (List<Resource>)dependencyResources.apply(graph, parameter, filter);
+            List<Resource> results = (List<Resource>)dependencyResources.apply(graph, parameter, filter);
             if (results == null || results.isEmpty())
                 return Collections.emptyList();
 
             if (TRACE_QUERIES)
                 System.out.println("  EntityInstances.QueryIndex: got " + results.size() + " results");
 
-//            // TreeSet to keep the results in deterministic order.
-//            Set<Resource> resultSet = new TreeSet<Resource>();
-//            for (Map<String, Object> entry : results) {
-//                Resource res = (Resource)entry.get("Resource");
-//                if (res != null && !resultSet.contains(res))
-//                    resultSet.add(res);
-//            }
+            // Optimize single result case.
+            if (results.size() == 1) {
+                Resource singleResult = results.get(0);
+                List<Resource> result = graph.isInstanceOf(singleResult, type) ? results : Collections.emptyList();
+                if (TRACE_QUERIES)
+                    System.out.println("  EntityInstances.QueryIndex: got " + results.size() + " unique type-matching results");
+                return result;
+            }
 
             CollectionSupport coll = graph.getService(CollectionSupport.class);
-            List<Resource> result = coll.createList();
-            
-            for (Resource res : Layer0Utils.sortByCluster(graph, results)) {
+            List<Resource> result = coll.createList(results.size());
+            for (Resource res : Layer0Utils.sortByCluster(graph, results))
                 if (graph.isInstanceOf(res, type))
                     result.add(res);
-            }
 
             if (TRACE_QUERIES)
                 System.out.println("  EntityInstances.QueryIndex: got " + results.size() + " unique type-matching results");
-            
+
             return result;
+        }
 
+        private String constructLuceneQuery(ReadGraph graph, Resource type, String filter) throws DatabaseException {
+            Layer0 L0 = Layer0.getInstance(graph);
+            StringBuilder sb = new StringBuilder();
+            if (!L0.Entity.equals(type)) {
+                String typeName = graph.getPossibleRelatedValue(type, L0.HasName, Bindings.STRING);
+                if (typeName == null || typeName.isEmpty())
+                    return null;
+                sb.append("Types:*").append( IndexQueries.escape( typeName, true ) );
+            }
+            if (filter.length() > 0) {
+                if (sb.length() > 0)
+                    sb.append(" AND ");
+                sb.append(filter);
+            }
+            return sb.toString();
         }
-        
+
         @Override
         public String toString() {
                return "QueryIndex " + parameter + " " + parameter2 + " " + parameter3;
index 5f9a8993ec61b313c2f57ca2438da6277be71348..37c89ff5f4dee3d0ac0a8fd0abd6b2a21207702b 100644 (file)
@@ -633,6 +633,11 @@ public class CollectionSupportImpl implements CollectionSupport {
                this.backend = new TIntArrayList();
        }
 
+       ResourceList(SessionImplSocket session, int capacity) {
+               this.session = session;
+               this.backend = new TIntArrayList(capacity);
+       }
+
        ResourceList(SessionImplSocket session, Collection<Resource> rs) {
                this.session = session;
                this.backend = new TIntArrayList(rs.size());
@@ -853,6 +858,11 @@ public class CollectionSupportImpl implements CollectionSupport {
                return new ResourceList(session);
        }
 
+       @Override
+       public List<Resource> createList(int capacity) {
+               return new ResourceList(session, capacity);
+       }
+
     static final class StatementList implements Collection<Statement> {
        
        final private SessionImplSocket session;
index aa522203d3a0a88eac043842a0deae436005a890..d5cebc8644d1e4bbf73fc4c9adfd3936a2cdfa20 100644 (file)
@@ -38,6 +38,7 @@ public interface CollectionSupport {
        Set<Resource> createSet();
        Set<Resource> createSet(int capacity);
        List<Resource> createList();
+       List<Resource> createList(int capacity);
        List<Resource> asSortedList(Collection<Resource> set);
        void sort(List<Resource> list);
        Collection<Statement> createStatementList();
index 511eeb3fa0e41fb0894b866d293cc330812c3923..2afdac9927aea060858b0b30f3a30c3d59ddaf87 100644 (file)
@@ -91,6 +91,7 @@ import org.simantics.db.layer0.adapter.CopyHandler;
 import org.simantics.db.layer0.adapter.GenericRelationIndex;
 import org.simantics.db.layer0.adapter.Instances;
 import org.simantics.db.layer0.adapter.impl.DefaultPasteImportAdvisor;
+import org.simantics.db.layer0.adapter.impl.EntityInstances.QueryIndex;
 import org.simantics.db.layer0.adapter.impl.ImportAdvisorFactory;
 import org.simantics.db.layer0.genericrelation.IndexedRelations;
 import org.simantics.db.layer0.migration.MigrationUtils;
@@ -704,7 +705,7 @@ public class ModelingUtils {
     }
 
     public static List<Resource> searchByTypeShallow(ReadGraph graph, Resource model, Resource type) throws DatabaseException {
-        return filterByIndexRoot(graph, model, searchByType(graph, model, type));
+        return graph.syncRequest(new QueryIndex(model, type, ""), TransientCacheListener.<List<Resource>>instance());
     }
 
     public static List<Resource> searchByType(ReadGraph graph, Resource model, Resource type) throws DatabaseException {
@@ -721,7 +722,7 @@ public class ModelingUtils {
     }
 
     public static List<Resource> searchByQueryShallow(ReadGraph graph, Resource model, String query) throws DatabaseException {
-        return filterByIndexRoot(graph, model, searchByQuery(graph, model, query));
+        return graph.syncRequest(new QueryIndex(model, Layer0.getInstance(graph).Entity, query), TransientCacheListener.<List<Resource>>instance());
     }
 
     public static List<Resource> searchByQuery(ReadGraph graph, Resource model, String query) throws DatabaseException {
@@ -774,7 +775,7 @@ public class ModelingUtils {
     }
 
     public static List<Resource> searchByTypeAndNameShallow(ReadGraph graph, Resource model, Resource type, String name) throws DatabaseException {
-        return filterByIndexRoot(graph, model, searchByTypeAndName(graph, model, type, name));
+        return graph.syncRequest(new QueryIndex(model, type, name), TransientCacheListener.<List<Resource>>instance());
     }
 
        /**