changeset 4977:dad71e6da406 more-tags

pre-filtering studies without ModalitiesInStudies first
author Alain Mazy <am@osimis.io>
date Wed, 20 Apr 2022 11:32:31 +0200
parents 03632ed1eb67
children 2cfa50d8eb60
files OrthancServer/Sources/OrthancConfiguration.h OrthancServer/Sources/OrthancRestApi/OrthancRestResources.cpp OrthancServer/Sources/Search/DatabaseLookup.cpp OrthancServer/Sources/Search/DatabaseLookup.h OrthancServer/Sources/ServerContext.cpp OrthancServer/Sources/ServerEnumerations.h
diffstat 6 files changed, 153 insertions(+), 11 deletions(-) [+]
line wrap: on
line diff
--- a/OrthancServer/Sources/OrthancConfiguration.h	Wed Apr 13 14:58:58 2022 +0200
+++ b/OrthancServer/Sources/OrthancConfiguration.h	Wed Apr 20 11:32:31 2022 +0200
@@ -27,6 +27,7 @@
 #include "../../OrthancFramework/Sources/DicomNetworking/RemoteModalityParameters.h"
 
 #include <OrthancServerResources.h>
+#include "ServerEnumerations.h"
 
 #include <boost/filesystem.hpp>
 #include <boost/thread/shared_mutex.hpp>
@@ -44,13 +45,6 @@
   class ServerIndex;
   class TemporaryFile;
 
-  enum Warnings
-  {
-    Warnings_None,
-    Warnings_001_TagsBeingReadFromStorage,
-    Warnings_002_InconsistentDicomTagsInDb,
-  };
-
 
   class OrthancConfiguration : public boost::noncopyable
   {
--- a/OrthancServer/Sources/OrthancRestApi/OrthancRestResources.cpp	Wed Apr 13 14:58:58 2022 +0200
+++ b/OrthancServer/Sources/OrthancRestApi/OrthancRestResources.cpp	Wed Apr 20 11:32:31 2022 +0200
@@ -2889,7 +2889,7 @@
                   bool expand,
                   const std::set<DicomTag>& requestedTags) const
       {
-        AnswerListOfResources(output, context, resources_, level, expand, format_, requestedTags);
+        AnswerListOfResources(output, context, resources_, instancesIds_, resourcesMainDicomTags_, resourcesDicomAsJson_, level, expand, format_, requestedTags);
       }
     };
   }
--- a/OrthancServer/Sources/Search/DatabaseLookup.cpp	Wed Apr 13 14:58:58 2022 +0200
+++ b/OrthancServer/Sources/Search/DatabaseLookup.cpp	Wed Apr 20 11:32:31 2022 +0200
@@ -326,4 +326,45 @@
 
     return false;
   }
+
+  bool DatabaseLookup::GetConstraint(const DicomTagConstraint*& constraint, const DicomTag& tag) const
+  {
+    for (size_t i = 0; i < constraints_.size(); i++)
+    {
+      assert(constraints_[i] != NULL);
+      if (constraints_[i]->GetTag() == tag)
+      {
+        constraint = constraints_.at(i);
+        return true;
+      }
+    }
+
+    return false;
+  }
+
+
+  void DatabaseLookup::RemoveConstraint(const DicomTag& tag)
+  {
+    for (size_t i = 0; i < constraints_.size(); i++)
+    {
+      assert(constraints_[i] != NULL);
+      if (constraints_[i]->GetTag() == tag)
+      {
+        delete constraints_[i];
+        constraints_.erase(constraints_.begin() + i);
+      }
+    }
+  }
+
+  DatabaseLookup* DatabaseLookup::Clone() const
+  {
+    std::unique_ptr<DatabaseLookup> clone(new DatabaseLookup());
+
+    for (size_t i = 0; i < constraints_.size(); i++)
+    {
+      clone->AddConstraint(*(new DicomTagConstraint(*constraints_[i])));
+    }
+
+    return clone.release();
+  }
 }
--- a/OrthancServer/Sources/Search/DatabaseLookup.h	Wed Apr 13 14:58:58 2022 +0200
+++ b/OrthancServer/Sources/Search/DatabaseLookup.h	Wed Apr 20 11:32:31 2022 +0200
@@ -48,6 +48,8 @@
 
     ~DatabaseLookup();
 
+    DatabaseLookup* Clone() const;
+
     void Reserve(size_t n)
     {
       constraints_.reserve(n);
@@ -60,6 +62,8 @@
 
     const DicomTagConstraint& GetConstraint(size_t index) const;
 
+    bool GetConstraint(const DicomTagConstraint*& constraint, const DicomTag& tag) const;
+
     bool IsMatch(const DicomMap& value) const;
 
     bool IsMatch(DcmItem& item,
@@ -86,5 +90,7 @@
     std::string Format() const;
 
     bool HasTag(const DicomTag& tag) const;
+
+    void RemoveConstraint(const DicomTag& tag);
   };
 }
--- a/OrthancServer/Sources/ServerContext.cpp	Wed Apr 13 14:58:58 2022 +0200
+++ b/OrthancServer/Sources/ServerContext.cpp	Wed Apr 20 11:32:31 2022 +0200
@@ -1670,9 +1670,104 @@
         }
       }
     };
+  
+# if 1
+    class StudyInstanceUidVisitor : public ServerContext::ILookupVisitor
+    {
+    private:
+      std::set<std::string>   studyInstanceUids;
+      
+    public:
+      explicit StudyInstanceUidVisitor()
+      {
+      }
+      
+      virtual bool IsDicomAsJsonNeeded() const ORTHANC_OVERRIDE
+      {
+        return false;
+      }
+      
+      virtual void MarkAsComplete() ORTHANC_OVERRIDE
+      {
+      }
+
+      virtual void Visit(const std::string& publicId,
+                         const std::string& instanceId,
+                         const DicomMap& mainDicomTags,
+                         const Json::Value* dicomAsJson)  ORTHANC_OVERRIDE
+      {
+        std::string studyInstanceUid;
+        if (!mainDicomTags.LookupStringValue(studyInstanceUid, DICOM_TAG_STUDY_INSTANCE_UID, false))
+        {
+          throw OrthancException(ErrorCode_InternalError);
+        }
+        studyInstanceUids.insert(studyInstanceUid);
+      }
+
+      const std::set<std::string>& GetFilteredStudyInstanceUids() const
+      {
+        return studyInstanceUids;
+      }
+    };
+  }
+
+  void ServerContext::Apply(ILookupVisitor& visitor,
+                            const DatabaseLookup& lookup,
+                            ResourceType queryLevel,
+                            size_t since,
+                            size_t limit)
+  {
+    const DicomTagConstraint* constraint = NULL;
+
+    if (queryLevel == ResourceType_Study &&
+        lookup.GetConstraint(constraint, DICOM_TAG_MODALITIES_IN_STUDY) &&
+        ((constraint->GetConstraintType() == ConstraintType_Equal && !constraint->GetValue().empty()) ||
+          (constraint->GetConstraintType() == ConstraintType_List && !constraint->GetValues().empty()))
+        )
+    {
+      std::unique_ptr<DatabaseLookup> studiesPreFilterLookup(lookup.Clone());
+      studiesPreFilterLookup->RemoveConstraint(DICOM_TAG_MODALITIES_IN_STUDY);
+
+      DatabaseLookup seriesLookup;
+
+      std::set<std::string> filteredStudyInstanceUids;
+      if (studiesPreFilterLookup->GetConstraintsCount() >= 1)
+      {
+        LOG(INFO) << "Performing First filtering without ModalitiesInStudy";
+
+        StudyInstanceUidVisitor studyVisitor;
+
+        ApplyInternal(studyVisitor, *studiesPreFilterLookup, queryLevel, since, limit);
+
+        DicomTagConstraint studyInstanceUidsConstraint(DICOM_TAG_STUDY_INSTANCE_UID, ConstraintType_List, true, true);
+        for (std::set<std::string>::const_iterator it = studyVisitor.GetFilteredStudyInstanceUids().begin();
+            it != studyVisitor.GetFilteredStudyInstanceUids().end(); it++)
+        {
+          studyInstanceUidsConstraint.AddValue(*it);
+        }
+
+        seriesLookup.AddConstraint(studyInstanceUidsConstraint);
+      }
+
+      // Convert the study-level query, into a series-level query,
+      // where "ModalitiesInStudy" is replaced by "Modality"
+      // and where all other constraints are replaced by "StudyInstanceUID IN (...)"
+
+      DicomTagConstraint modality(*constraint);
+      modality.SetTag(DICOM_TAG_MODALITY);
+      seriesLookup.AddConstraint(modality);
+
+      ModalitiesInStudyVisitor seriesVisitor(visitor.IsDicomAsJsonNeeded());
+      ApplyInternal(seriesVisitor, seriesLookup, ResourceType_Series, 0, 0);
+      seriesVisitor.Forward(visitor, since, limit);
+    }
+    else  // filtering without ModalitiesInStudy
+    {
+      ApplyInternal(visitor, lookup, queryLevel, since, limit);
+    }
   }
   
-
+#else
   void ServerContext::Apply(ILookupVisitor& visitor,
                             const DatabaseLookup& lookup,
                             ResourceType queryLevel,
@@ -1720,8 +1815,8 @@
     {
       ApplyInternal(visitor, lookup, queryLevel, since, limit);
     }
-  }
-  
+  }  
+#endif
 
   bool ServerContext::LookupOrReconstructMetadata(std::string& target,
                                                   const std::string& publicId,
--- a/OrthancServer/Sources/ServerEnumerations.h	Wed Apr 13 14:58:58 2022 +0200
+++ b/OrthancServer/Sources/ServerEnumerations.h	Wed Apr 20 11:32:31 2022 +0200
@@ -191,6 +191,12 @@
     BuiltinDecoderTranscoderOrder_Disabled
   };
 
+  enum Warnings
+  {
+    Warnings_None,
+    Warnings_001_TagsBeingReadFromStorage,
+    Warnings_002_InconsistentDicomTagsInDb,
+  };
 
 
   void InitializeServerEnumerations();