# HG changeset patch # User Alain Mazy # Date 1650447151 -7200 # Node ID dad71e6da4066bc452f79f8313c13b0d0d492981 # Parent 03632ed1eb6756efd45b559bbb557ecd4a0f3a83 pre-filtering studies without ModalitiesInStudies first diff -r 03632ed1eb67 -r dad71e6da406 OrthancServer/Sources/OrthancConfiguration.h --- 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 +#include "ServerEnumerations.h" #include #include @@ -44,13 +45,6 @@ class ServerIndex; class TemporaryFile; - enum Warnings - { - Warnings_None, - Warnings_001_TagsBeingReadFromStorage, - Warnings_002_InconsistentDicomTagsInDb, - }; - class OrthancConfiguration : public boost::noncopyable { diff -r 03632ed1eb67 -r dad71e6da406 OrthancServer/Sources/OrthancRestApi/OrthancRestResources.cpp --- 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& requestedTags) const { - AnswerListOfResources(output, context, resources_, level, expand, format_, requestedTags); + AnswerListOfResources(output, context, resources_, instancesIds_, resourcesMainDicomTags_, resourcesDicomAsJson_, level, expand, format_, requestedTags); } }; } diff -r 03632ed1eb67 -r dad71e6da406 OrthancServer/Sources/Search/DatabaseLookup.cpp --- 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 clone(new DatabaseLookup()); + + for (size_t i = 0; i < constraints_.size(); i++) + { + clone->AddConstraint(*(new DicomTagConstraint(*constraints_[i]))); + } + + return clone.release(); + } } diff -r 03632ed1eb67 -r dad71e6da406 OrthancServer/Sources/Search/DatabaseLookup.h --- 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); }; } diff -r 03632ed1eb67 -r dad71e6da406 OrthancServer/Sources/ServerContext.cpp --- 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 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& 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 studiesPreFilterLookup(lookup.Clone()); + studiesPreFilterLookup->RemoveConstraint(DICOM_TAG_MODALITIES_IN_STUDY); + + DatabaseLookup seriesLookup; + + std::set 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::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, diff -r 03632ed1eb67 -r dad71e6da406 OrthancServer/Sources/ServerEnumerations.h --- 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();