diff OrthancServer/OrthancFindRequestHandler.cpp @ 615:ec0b7a51d7bd find-move-scp

speed up find
author Sebastien Jodogne <s.jodogne@gmail.com>
date Thu, 24 Oct 2013 11:42:46 +0200
parents fdd5f7f9c4d7
children 5ab377df6d8b
line wrap: on
line diff
--- a/OrthancServer/OrthancFindRequestHandler.cpp	Thu Oct 24 10:33:11 2013 +0200
+++ b/OrthancServer/OrthancFindRequestHandler.cpp	Thu Oct 24 11:42:46 2013 +0200
@@ -39,6 +39,14 @@
 
 namespace Orthanc
 {
+  static bool IsWildcard(const std::string& constraint)
+  {
+    return (constraint.find('-') != std::string::npos ||
+            constraint.find('*') != std::string::npos ||
+            constraint.find('\\') != std::string::npos ||
+            constraint.find('?') != std::string::npos);
+  }
+
   static std::string ToLowerCase(const std::string& s)
   {
     std::string result = s;
@@ -209,12 +217,12 @@
   }
 
 
-  static bool ApplyModalitiesInStudyFilter(Json::Value& filteredStudies,
-                                           const Json::Value& studies,
+  static bool ApplyModalitiesInStudyFilter(std::list<std::string>& filteredStudies,
+                                           const std::list<std::string>& studies,
                                            const DicomMap& input,
                                            ServerIndex& index)
   {
-    filteredStudies = Json::arrayValue;
+    filteredStudies.clear();
 
     const DicomValue& v = input.GetValue(DICOM_TAG_MODALITIES_IN_STUDY);
     if (v.IsNull())
@@ -233,14 +241,15 @@
     }
 
     // Loop over the studies
-    for (Json::Value::ArrayIndex i = 0; i < studies.size(); i++)
+    for (std::list<std::string>::const_iterator 
+           it = studies.begin(); it != studies.end(); it++)
     {
       try
       {
         // We are considering a single study. Check whether one of
         // its child series matches one of the modalities.
         Json::Value study;
-        if (index.LookupResource(study, studies[i].asString(), ResourceType_Study))
+        if (index.LookupResource(study, *it, ResourceType_Study))
         {
           // Loop over the series of the considered study.
           for (Json::Value::ArrayIndex j = 0; j < study["Series"].size(); j++)   // (*)
@@ -257,7 +266,7 @@
                   // This series of the considered study matches one
                   // of the required modalities. Take the study into
                   // consideration for future filtering.
-                  filteredStudies.append(studies[i]);
+                  filteredStudies.push_back(*it);
 
                   // We have finished considering this study. Break the study loop at (*).
                   break;
@@ -277,6 +286,78 @@
   }
 
 
+  static bool LookupCandidateResourcesInternal(/* out */ std::list<std::string>& resources,
+                                               /* in */  ServerIndex& index,
+                                               /* in */  ResourceType level,
+                                               /* in */  const DicomMap& query,
+                                               /* in */  DicomTag tag)
+  {
+    if (query.HasTag(tag))
+    {
+      const DicomValue& value = query.GetValue(tag);
+      if (!value.IsNull())
+      {
+        std::string str = query.GetValue(tag).AsString();
+        if (!IsWildcard(str))
+        {
+          printf(">> [%s]\n", str.c_str());
+          index.LookupTagValue(resources, tag, str/*, level*/);
+          return true;
+        }
+      }
+    }
+
+    return false;
+  }
+
+
+  static void LookupCandidateResources(/* out */ std::list<std::string>& resources,
+                                       /* in */  ServerIndex& index,
+                                       /* in */  ResourceType level,
+                                       /* in */  const DicomMap& query)
+  {
+    // TODO : Speed up using full querying against the MainDicomTags.
+
+    resources.clear();
+
+    bool done = false;
+
+    switch (level)
+    {
+      case ResourceType_Patient:
+        done = LookupCandidateResourcesInternal(resources, index, level, query, DICOM_TAG_PATIENT_ID);
+        break;
+
+      case ResourceType_Study:
+        done = LookupCandidateResourcesInternal(resources, index, level, query, DICOM_TAG_STUDY_INSTANCE_UID);
+        break;
+
+      case ResourceType_Series:
+        done = LookupCandidateResourcesInternal(resources, index, level, query, DICOM_TAG_SERIES_INSTANCE_UID);
+        break;
+
+      case ResourceType_Instance:
+        done = LookupCandidateResourcesInternal(resources, index, level, query, DICOM_TAG_SOP_INSTANCE_UID);
+        break;
+
+      default:
+        break;
+    }
+
+    if (!done)
+    {
+      Json::Value allResources;
+      index.GetAllUuids(allResources, level);
+      assert(allResources.type() == Json::arrayValue);
+
+      for (Json::Value::ArrayIndex i = 0; i < allResources.size(); i++)
+      {
+        resources.push_back(allResources[i].asString());
+      }
+    }
+  }
+
+
   void OrthancFindRequestHandler::Handle(const DicomMap& input,
                                          DicomFindAnswers& answers)
   {
@@ -303,16 +384,14 @@
 
 
     /**
-     * Retrieve all the resources for this query level.
+     * Retrieve the candidate resources for this query level. Whenever
+     * possible, we avoid returning ALL the resources for this query
+     * level, as it would imply reading the JSON file on the harddisk
+     * for each of them.
      **/
 
-    Json::Value resources;
-    context_.GetIndex().GetAllUuids(resources, level);
-    assert(resources.type() == Json::arrayValue);
-
-    // TODO : Speed up using MainDicomTags (to avoid looping over ALL
-    // the resources and reading the JSON file for each of them)
-
+    std::list<std::string>  resources;
+    LookupCandidateResources(resources, context_.GetIndex(), level, input);
 
 
     /**
@@ -324,7 +403,7 @@
     if (level == ResourceType_Study &&
         input.HasTag(DICOM_TAG_MODALITIES_IN_STUDY))
     {
-      Json::Value filtered;
+      std::list<std::string> filtered;
       if (ApplyModalitiesInStudyFilter(filtered, resources, input, context_.GetIndex()))
       {
         resources = filtered;
@@ -337,19 +416,20 @@
      **/
 
     DicomArray query(input);
-    for (Json::Value::ArrayIndex i = 0; i < resources.size(); i++)
+    for (std::list<std::string>::const_iterator 
+           resource = resources.begin(); resource != resources.end(); resource++)
     {
       try
       {
         std::string instance;
-        if (LookupOneInstance(instance, context_.GetIndex(), resources[i].asString(), level))
+        if (LookupOneInstance(instance, context_.GetIndex(), *resource, level))
         {
-          Json::Value resource;
-          context_.ReadJson(resource, instance);
+          Json::Value info;
+          context_.ReadJson(info, instance);
         
-          if (Matches(resource, query))
+          if (Matches(info, query))
           {
-            AddAnswer(answers, resource, query);
+            AddAnswer(answers, info, query);
           }
         }
       }