changeset 5866:5c484b4f99d5 find-refactoring tip

trying to speed up count of children
author Alain Mazy <am@orthanc.team>
date Wed, 06 Nov 2024 19:25:30 +0100
parents 083dac252b01
children
files OrthancServer/Plugins/Engine/OrthancPluginDatabaseV4.cpp OrthancServer/Plugins/Include/orthanc/OrthancDatabasePlugin.proto OrthancServer/Sources/Database/FindRequest.h OrthancServer/Sources/Database/FindResponse.h OrthancServer/Sources/Database/SQLiteDatabaseWrapper.cpp OrthancServer/Sources/ResourceFinder.cpp
diffstat 6 files changed, 140 insertions(+), 10 deletions(-) [+]
line wrap: on
line diff
--- a/OrthancServer/Plugins/Engine/OrthancPluginDatabaseV4.cpp	Wed Nov 06 08:51:02 2024 +0100
+++ b/OrthancServer/Plugins/Engine/OrthancPluginDatabaseV4.cpp	Wed Nov 06 19:25:30 2024 +0100
@@ -291,6 +291,7 @@
                       const FindRequest::ChildrenSpecification& source)
   {
     target.set_retrieve_identifiers(source.IsRetrieveIdentifiers());
+    target.set_retrieve_count(source.IsRetrieveCount());
 
     for (std::set<MetadataType>::const_iterator it = source.GetMetadata().begin(); it != source.GetMetadata().end(); ++it)
     {
@@ -333,6 +334,8 @@
       target.AddChildIdentifier(level, source.identifiers(i));
     }
 
+    target.SetChildrenCount(level, source.count());
+
     for (int i = 0; i < source.main_dicom_tags().size(); i++)
     {
       const DicomTag tag(source.main_dicom_tags(i).group(), source.main_dicom_tags(i).element());
--- a/OrthancServer/Plugins/Include/orthanc/OrthancDatabasePlugin.proto	Wed Nov 06 08:51:02 2024 +0100
+++ b/OrthancServer/Plugins/Include/orthanc/OrthancDatabasePlugin.proto	Wed Nov 06 19:25:30 2024 +0100
@@ -877,6 +877,7 @@
       bool retrieve_identifiers = 1;
       repeated int32 retrieve_metadata = 2;
       repeated Tag retrieve_main_dicom_tags = 3;
+      bool retrieve_count = 4;
     }
     message Ordering {
       OrderingKeyType key_type = 1;
@@ -945,6 +946,7 @@
       repeated string identifiers = 1;
       repeated MultipleTags main_dicom_tags = 2;
       repeated MultipleMetadata metadata = 3;
+      uint64 count = 4;
     }
 
     int64 internal_id = 1;
--- a/OrthancServer/Sources/Database/FindRequest.h	Wed Nov 06 08:51:02 2024 +0100
+++ b/OrthancServer/Sources/Database/FindRequest.h	Wed Nov 06 19:25:30 2024 +0100
@@ -185,10 +185,12 @@
       bool                    identifiers_;
       std::set<MetadataType>  metadata_;
       std::set<DicomTag>      mainDicomTags_;
+      bool                    count_;
 
     public:
       ChildrenSpecification() :
-        identifiers_(false)
+        identifiers_(false),
+        count_(false)
       {
       }
 
@@ -202,6 +204,16 @@
         return identifiers_;
       }
 
+      void SetRetrieveCount(bool retrieve)
+      {
+        count_ = retrieve;
+      }
+
+      bool IsRetrieveCount() const
+      {
+        return count_;
+      }
+
       void AddMetadata(MetadataType metadata)
       {
         metadata_.insert(metadata);
--- a/OrthancServer/Sources/Database/FindResponse.h	Wed Nov 06 08:51:02 2024 +0100
+++ b/OrthancServer/Sources/Database/FindResponse.h	Wed Nov 06 19:25:30 2024 +0100
@@ -73,10 +73,16 @@
       typedef std::map<DicomTag, std::set<std::string>* >      MainDicomTagValues;
 
       std::set<std::string>  identifiers_;
+      uint64_t               count_;
       MetadataValues         metadataValues_;
       MainDicomTagValues     mainDicomTagValues_;
 
     public:
+      ChildrenInformation()
+      : count_(0)
+      {
+      }
+
       ~ChildrenInformation();
 
       void AddIdentifier(const std::string& identifier);
@@ -86,6 +92,16 @@
         return identifiers_;
       }
 
+      void SetCount(uint64_t count)
+      {
+        count_ = count;
+      }
+
+      uint64_t GetCount() const
+      {
+        return count_;
+      }
+
       void AddMetadataValue(MetadataType metadata,
                             const std::string& value);
 
@@ -272,6 +288,17 @@
         return GetChildrenInformation(level).GetIdentifiers();
       }
 
+      void SetChildrenCount(ResourceType level,
+                            uint64_t count)
+      {
+        GetChildrenInformation(level).SetCount(count);
+      }
+
+      uint64_t GetChildrenCount(ResourceType level) const
+      {
+        return GetChildrenInformation(level).GetCount();
+      }
+
       void AddChildrenMetadataValue(ResourceType level,
                                     MetadataType metadata,
                                     const std::string& value)
--- a/OrthancServer/Sources/Database/SQLiteDatabaseWrapper.cpp	Wed Nov 06 08:51:02 2024 +0100
+++ b/OrthancServer/Sources/Database/SQLiteDatabaseWrapper.cpp	Wed Nov 06 19:25:30 2024 +0100
@@ -491,10 +491,13 @@
 #define QUERY_CHILDREN_IDENTIFIERS 20
 #define QUERY_CHILDREN_MAIN_DICOM_TAGS 21
 #define QUERY_CHILDREN_METADATA 22
+#define QUERY_CHILDREN_COUNT 23
 #define QUERY_GRAND_CHILDREN_IDENTIFIERS 30
 #define QUERY_GRAND_CHILDREN_MAIN_DICOM_TAGS 31
 #define QUERY_GRAND_CHILDREN_METADATA 32
+#define QUERY_GRAND_CHILDREN_COUNT 33
 #define QUERY_GRAND_GRAND_CHILDREN_IDENTIFIERS 40
+#define QUERY_GRAND_GRAND_CHILDREN_COUNT 41
 #define QUERY_ONE_INSTANCE_IDENTIFIER 50
 #define QUERY_ONE_INSTANCE_METADATA 51
 #define QUERY_ONE_INSTANCE_ATTACHMENTS 52
@@ -911,6 +914,25 @@
                "FROM Lookup "
                "  INNER JOIN Resources childLevel ON Lookup.internalId = childLevel.parentId ";
       }
+      // no need to count if we have retrieved the list of identifiers
+      else if ((requestLevel == ResourceType_Patient && request.GetChildrenSpecification(ResourceType_Study).IsRetrieveCount()) ||
+          (requestLevel == ResourceType_Study && request.GetChildrenSpecification(ResourceType_Series).IsRetrieveCount()) ||
+          (requestLevel == ResourceType_Series && request.GetChildrenSpecification(ResourceType_Instance).IsRetrieveCount()))
+      {
+        sql += "UNION SELECT "
+               "  " TOSTRING(QUERY_CHILDREN_COUNT) " AS c0_queryId, "
+               "  Lookup.internalId AS c1_internalId, "
+               "  NULL AS c2_rowNumber, "
+               "  NULL AS c3_string1, "
+               "  NULL AS c4_string2, "
+               "  NULL AS c5_string3, "
+               "  COUNT(*) AS c6_int1, "
+               "  NULL AS c7_int2, "
+               "  NULL AS c8_big_int1, "
+               "  NULL AS c9_big_int2 "
+               "FROM Lookup "
+               "  INNER JOIN Resources childLevel ON Lookup.internalId = childLevel.parentId GROUP BY Lookup.internalId ";
+      }
 
       // need grandchildren identifiers ?
       if ((requestLevel == ResourceType_Patient && request.GetChildrenSpecification(ResourceType_Series).IsRetrieveIdentifiers()) ||
@@ -931,6 +953,25 @@
               "INNER JOIN Resources childLevel ON Lookup.internalId = childLevel.parentId "
               "INNER JOIN Resources grandChildLevel ON childLevel.internalId = grandChildLevel.parentId ";
       }
+      // no need to count if we have retrieved the list of identifiers
+      else if ((requestLevel == ResourceType_Patient && request.GetChildrenSpecification(ResourceType_Series).IsRetrieveCount()) ||
+          (requestLevel == ResourceType_Study && request.GetChildrenSpecification(ResourceType_Instance).IsRetrieveCount()))
+      {
+        sql += "UNION SELECT "
+              "  " TOSTRING(QUERY_GRAND_CHILDREN_COUNT) " AS c0_queryId, "
+              "  Lookup.internalId AS c1_internalId, "
+              "  NULL AS c2_rowNumber, "
+              "  NULL AS c3_string1, "
+              "  NULL AS c4_string2, "
+              "  NULL AS c5_string3, "
+               "  COUNT(*) AS c6_int1, "
+              "  NULL AS c7_int2, "
+              "  NULL AS c8_big_int1, "
+              "  NULL AS c9_big_int2 "
+              "FROM Lookup "
+              "INNER JOIN Resources childLevel ON Lookup.internalId = childLevel.parentId "
+              "INNER JOIN Resources grandChildLevel ON childLevel.internalId = grandChildLevel.parentId GROUP BY Lookup.internalId ";
+      }
 
       // need grandgrandchildren identifiers ?
       if (requestLevel == ResourceType_Patient && request.GetChildrenSpecification(ResourceType_Instance).IsRetrieveIdentifiers())
@@ -951,6 +992,25 @@
               "INNER JOIN Resources grandChildLevel ON childLevel.internalId = grandChildLevel.parentId "
               "INNER JOIN Resources grandGrandChildLevel ON grandChildLevel.internalId = grandGrandChildLevel.parentId ";
       }
+      // no need to count if we have retrieved the list of identifiers
+      else if (requestLevel == ResourceType_Patient && request.GetChildrenSpecification(ResourceType_Instance).IsRetrieveCount())
+      {
+        sql += "UNION SELECT "
+              "  " TOSTRING(QUERY_GRAND_GRAND_CHILDREN_COUNT) " AS c0_queryId, "
+              "  Lookup.internalId AS c1_internalId, "
+              "  NULL AS c2_rowNumber, "
+              "  NULL AS c3_string1, "
+              "  NULL AS c4_string2, "
+              "  NULL AS c5_string3, "
+               "  COUNT(*) AS c6_int1, "
+              "  NULL AS c7_int2, "
+              "  NULL AS c8_big_int1, "
+              "  NULL AS c9_big_int2 "
+              "FROM Lookup "
+              "INNER JOIN Resources childLevel ON Lookup.internalId = childLevel.parentId "
+              "INNER JOIN Resources grandChildLevel ON childLevel.internalId = grandChildLevel.parentId "
+              "INNER JOIN Resources grandGrandChildLevel ON grandChildLevel.internalId = grandGrandChildLevel.parentId GROUP BY Lookup.internalId ";
+      }
 
 
       sql += " ORDER BY c0_queryId, c2_rowNumber";  // this is really important to make sure that the Lookup query is the first one to provide results since we use it to create the responses element !
@@ -983,10 +1043,10 @@
           case QUERY_ATTACHMENTS:
           {
             FindResponse::Resource& res = response.GetResourceByInternalId(internalId);
-            FileInfo file(s.ColumnString(C3_STRING_1), static_cast<FileContentType>(s.ColumnInt(C6_INT_1)), 
-                          s.ColumnInt64(C8_BIG_INT_1), s.ColumnString(C4_STRING_2),
+            FileInfo file(s.ColumnString(C3_STRING_1), static_cast<FileContentType>(s.ColumnInt(C6_INT_1)),
+                          s.ColumnInt64(C9_BIG_INT_2), s.ColumnString(C4_STRING_2),
                           static_cast<CompressionType>(s.ColumnInt(C7_INT_2)),
-                          s.ColumnInt64(C9_BIG_INT_2), s.ColumnString(C5_STRING_3));
+                          s.ColumnInt64(C8_BIG_INT_1), s.ColumnString(C5_STRING_3));
             res.AddAttachment(file, 0 /* TODO - REVISIONS */);
           }; break;
 
@@ -1084,6 +1144,8 @@
             FindResponse::Resource& res = response.GetResourceByInternalId(internalId);
             res.AddChildIdentifier(static_cast<ResourceType>(requestLevel + 1),
                                    s.ColumnString(C3_STRING_1));
+            res.SetChildrenCount(static_cast<ResourceType>(requestLevel + 1),
+                                 res.GetChildrenIdentifiers(static_cast<ResourceType>(requestLevel + 1)).size());
           }; break;
 
           case QUERY_GRAND_CHILDREN_IDENTIFIERS:
@@ -1091,6 +1153,8 @@
             FindResponse::Resource& res = response.GetResourceByInternalId(internalId);
             res.AddChildIdentifier(static_cast<ResourceType>(requestLevel + 2),
                                    s.ColumnString(C3_STRING_1));
+            res.SetChildrenCount(static_cast<ResourceType>(requestLevel + 2),
+                                 res.GetChildrenIdentifiers(static_cast<ResourceType>(requestLevel + 2)).size());
           }; break;
 
           case QUERY_GRAND_GRAND_CHILDREN_IDENTIFIERS:
@@ -1098,6 +1162,29 @@
             FindResponse::Resource& res = response.GetResourceByInternalId(internalId);
             res.AddChildIdentifier(static_cast<ResourceType>(requestLevel + 3),
                                    s.ColumnString(C3_STRING_1));
+            res.SetChildrenCount(static_cast<ResourceType>(requestLevel + 3),
+                                 res.GetChildrenIdentifiers(static_cast<ResourceType>(requestLevel + 3)).size());
+          }; break;
+
+          case QUERY_CHILDREN_COUNT:
+          {
+            FindResponse::Resource& res = response.GetResourceByInternalId(internalId);
+            res.SetChildrenCount(static_cast<ResourceType>(requestLevel + 1),
+                                 static_cast<uint64_t>(s.ColumnInt64(C6_INT_1)));
+          }; break;
+
+          case QUERY_GRAND_CHILDREN_COUNT:
+          {
+            FindResponse::Resource& res = response.GetResourceByInternalId(internalId);
+            res.SetChildrenCount(static_cast<ResourceType>(requestLevel + 2),
+                                 static_cast<uint64_t>(s.ColumnInt64(C6_INT_1)));
+          }; break;
+
+          case QUERY_GRAND_GRAND_CHILDREN_COUNT:
+          {
+            FindResponse::Resource& res = response.GetResourceByInternalId(internalId);
+            res.SetChildrenCount(static_cast<ResourceType>(requestLevel + 3),
+                                 static_cast<uint64_t>(s.ColumnInt64(C6_INT_1)));
           }; break;
 
           case QUERY_ONE_INSTANCE_IDENTIFIER:
@@ -1115,10 +1202,10 @@
           case QUERY_ONE_INSTANCE_ATTACHMENTS:
           {
             FindResponse::Resource& res = response.GetResourceByInternalId(internalId);
-            FileInfo file(s.ColumnString(C3_STRING_1), static_cast<FileContentType>(s.ColumnInt(C6_INT_1)), 
-                          s.ColumnInt64(C8_BIG_INT_1), s.ColumnString(C4_STRING_2),
+            FileInfo file(s.ColumnString(C3_STRING_1), static_cast<FileContentType>(s.ColumnInt(C6_INT_1)),
+                          s.ColumnInt64(C9_BIG_INT_2), s.ColumnString(C4_STRING_2),
                           static_cast<CompressionType>(s.ColumnInt(C7_INT_2)),
-                          s.ColumnInt64(C9_BIG_INT_2), s.ColumnString(C5_STRING_3));
+                          s.ColumnInt64(C8_BIG_INT_1), s.ColumnString(C5_STRING_3));
             res.AddOneInstanceAttachment(file);
           }; break;
 
--- a/OrthancServer/Sources/ResourceFinder.cpp	Wed Nov 06 08:51:02 2024 +0100
+++ b/OrthancServer/Sources/ResourceFinder.cpp	Wed Nov 06 19:25:30 2024 +0100
@@ -56,7 +56,7 @@
     if (request_.GetLevel() == parentLevel)
     {
       requestedComputedTags_.insert(tag);
-      request_.GetChildrenSpecification(childLevel).SetRetrieveIdentifiers(true);
+      request_.GetChildrenSpecification(childLevel).SetRetrieveCount(true);
     }
   }
 
@@ -68,8 +68,7 @@
   {
     if (IsRequestedComputedTag(tag))
     {
-      const std::set<std::string>& children = resource.GetChildrenIdentifiers(level);
-      requestedTags.SetValue(tag, boost::lexical_cast<std::string>(children.size()), false);
+      requestedTags.SetValue(tag, boost::lexical_cast<std::string>(resource.GetChildrenCount(level)), false);
     }
   }