comparison 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
comparison
equal deleted inserted replaced
614:f27923072afd 615:ec0b7a51d7bd
37 #include "../Core/DicomFormat/DicomArray.h" 37 #include "../Core/DicomFormat/DicomArray.h"
38 #include "ServerToolbox.h" 38 #include "ServerToolbox.h"
39 39
40 namespace Orthanc 40 namespace Orthanc
41 { 41 {
42 static bool IsWildcard(const std::string& constraint)
43 {
44 return (constraint.find('-') != std::string::npos ||
45 constraint.find('*') != std::string::npos ||
46 constraint.find('\\') != std::string::npos ||
47 constraint.find('?') != std::string::npos);
48 }
49
42 static std::string ToLowerCase(const std::string& s) 50 static std::string ToLowerCase(const std::string& s)
43 { 51 {
44 std::string result = s; 52 std::string result = s;
45 Toolbox::ToLowerCase(result); 53 Toolbox::ToLowerCase(result);
46 return result; 54 return result;
207 215
208 answers.Add(result); 216 answers.Add(result);
209 } 217 }
210 218
211 219
212 static bool ApplyModalitiesInStudyFilter(Json::Value& filteredStudies, 220 static bool ApplyModalitiesInStudyFilter(std::list<std::string>& filteredStudies,
213 const Json::Value& studies, 221 const std::list<std::string>& studies,
214 const DicomMap& input, 222 const DicomMap& input,
215 ServerIndex& index) 223 ServerIndex& index)
216 { 224 {
217 filteredStudies = Json::arrayValue; 225 filteredStudies.clear();
218 226
219 const DicomValue& v = input.GetValue(DICOM_TAG_MODALITIES_IN_STUDY); 227 const DicomValue& v = input.GetValue(DICOM_TAG_MODALITIES_IN_STUDY);
220 if (v.IsNull()) 228 if (v.IsNull())
221 { 229 {
222 return false; 230 return false;
231 { 239 {
232 modalities.insert(tmp[i]); 240 modalities.insert(tmp[i]);
233 } 241 }
234 242
235 // Loop over the studies 243 // Loop over the studies
236 for (Json::Value::ArrayIndex i = 0; i < studies.size(); i++) 244 for (std::list<std::string>::const_iterator
245 it = studies.begin(); it != studies.end(); it++)
237 { 246 {
238 try 247 try
239 { 248 {
240 // We are considering a single study. Check whether one of 249 // We are considering a single study. Check whether one of
241 // its child series matches one of the modalities. 250 // its child series matches one of the modalities.
242 Json::Value study; 251 Json::Value study;
243 if (index.LookupResource(study, studies[i].asString(), ResourceType_Study)) 252 if (index.LookupResource(study, *it, ResourceType_Study))
244 { 253 {
245 // Loop over the series of the considered study. 254 // Loop over the series of the considered study.
246 for (Json::Value::ArrayIndex j = 0; j < study["Series"].size(); j++) // (*) 255 for (Json::Value::ArrayIndex j = 0; j < study["Series"].size(); j++) // (*)
247 { 256 {
248 Json::Value series; 257 Json::Value series;
255 if (modalities.find(modality) != modalities.end()) 264 if (modalities.find(modality) != modalities.end())
256 { 265 {
257 // This series of the considered study matches one 266 // This series of the considered study matches one
258 // of the required modalities. Take the study into 267 // of the required modalities. Take the study into
259 // consideration for future filtering. 268 // consideration for future filtering.
260 filteredStudies.append(studies[i]); 269 filteredStudies.push_back(*it);
261 270
262 // We have finished considering this study. Break the study loop at (*). 271 // We have finished considering this study. Break the study loop at (*).
263 break; 272 break;
264 } 273 }
265 } 274 }
275 284
276 return true; 285 return true;
277 } 286 }
278 287
279 288
289 static bool LookupCandidateResourcesInternal(/* out */ std::list<std::string>& resources,
290 /* in */ ServerIndex& index,
291 /* in */ ResourceType level,
292 /* in */ const DicomMap& query,
293 /* in */ DicomTag tag)
294 {
295 if (query.HasTag(tag))
296 {
297 const DicomValue& value = query.GetValue(tag);
298 if (!value.IsNull())
299 {
300 std::string str = query.GetValue(tag).AsString();
301 if (!IsWildcard(str))
302 {
303 printf(">> [%s]\n", str.c_str());
304 index.LookupTagValue(resources, tag, str/*, level*/);
305 return true;
306 }
307 }
308 }
309
310 return false;
311 }
312
313
314 static void LookupCandidateResources(/* out */ std::list<std::string>& resources,
315 /* in */ ServerIndex& index,
316 /* in */ ResourceType level,
317 /* in */ const DicomMap& query)
318 {
319 // TODO : Speed up using full querying against the MainDicomTags.
320
321 resources.clear();
322
323 bool done = false;
324
325 switch (level)
326 {
327 case ResourceType_Patient:
328 done = LookupCandidateResourcesInternal(resources, index, level, query, DICOM_TAG_PATIENT_ID);
329 break;
330
331 case ResourceType_Study:
332 done = LookupCandidateResourcesInternal(resources, index, level, query, DICOM_TAG_STUDY_INSTANCE_UID);
333 break;
334
335 case ResourceType_Series:
336 done = LookupCandidateResourcesInternal(resources, index, level, query, DICOM_TAG_SERIES_INSTANCE_UID);
337 break;
338
339 case ResourceType_Instance:
340 done = LookupCandidateResourcesInternal(resources, index, level, query, DICOM_TAG_SOP_INSTANCE_UID);
341 break;
342
343 default:
344 break;
345 }
346
347 if (!done)
348 {
349 Json::Value allResources;
350 index.GetAllUuids(allResources, level);
351 assert(allResources.type() == Json::arrayValue);
352
353 for (Json::Value::ArrayIndex i = 0; i < allResources.size(); i++)
354 {
355 resources.push_back(allResources[i].asString());
356 }
357 }
358 }
359
360
280 void OrthancFindRequestHandler::Handle(const DicomMap& input, 361 void OrthancFindRequestHandler::Handle(const DicomMap& input,
281 DicomFindAnswers& answers) 362 DicomFindAnswers& answers)
282 { 363 {
283 LOG(WARNING) << "Find-SCU request received"; 364 LOG(WARNING) << "Find-SCU request received";
284 365
301 throw OrthancException(ErrorCode_NotImplemented); 382 throw OrthancException(ErrorCode_NotImplemented);
302 } 383 }
303 384
304 385
305 /** 386 /**
306 * Retrieve all the resources for this query level. 387 * Retrieve the candidate resources for this query level. Whenever
388 * possible, we avoid returning ALL the resources for this query
389 * level, as it would imply reading the JSON file on the harddisk
390 * for each of them.
307 **/ 391 **/
308 392
309 Json::Value resources; 393 std::list<std::string> resources;
310 context_.GetIndex().GetAllUuids(resources, level); 394 LookupCandidateResources(resources, context_.GetIndex(), level, input);
311 assert(resources.type() == Json::arrayValue);
312
313 // TODO : Speed up using MainDicomTags (to avoid looping over ALL
314 // the resources and reading the JSON file for each of them)
315
316 395
317 396
318 /** 397 /**
319 * Apply filtering on modalities for studies, if asked (this is an 398 * Apply filtering on modalities for studies, if asked (this is an
320 * extension to standard DICOM) 399 * extension to standard DICOM)
322 **/ 401 **/
323 402
324 if (level == ResourceType_Study && 403 if (level == ResourceType_Study &&
325 input.HasTag(DICOM_TAG_MODALITIES_IN_STUDY)) 404 input.HasTag(DICOM_TAG_MODALITIES_IN_STUDY))
326 { 405 {
327 Json::Value filtered; 406 std::list<std::string> filtered;
328 if (ApplyModalitiesInStudyFilter(filtered, resources, input, context_.GetIndex())) 407 if (ApplyModalitiesInStudyFilter(filtered, resources, input, context_.GetIndex()))
329 { 408 {
330 resources = filtered; 409 resources = filtered;
331 } 410 }
332 } 411 }
335 /** 414 /**
336 * Loop over all the resources for this query level. 415 * Loop over all the resources for this query level.
337 **/ 416 **/
338 417
339 DicomArray query(input); 418 DicomArray query(input);
340 for (Json::Value::ArrayIndex i = 0; i < resources.size(); i++) 419 for (std::list<std::string>::const_iterator
420 resource = resources.begin(); resource != resources.end(); resource++)
341 { 421 {
342 try 422 try
343 { 423 {
344 std::string instance; 424 std::string instance;
345 if (LookupOneInstance(instance, context_.GetIndex(), resources[i].asString(), level)) 425 if (LookupOneInstance(instance, context_.GetIndex(), *resource, level))
346 { 426 {
347 Json::Value resource; 427 Json::Value info;
348 context_.ReadJson(resource, instance); 428 context_.ReadJson(info, instance);
349 429
350 if (Matches(resource, query)) 430 if (Matches(info, query))
351 { 431 {
352 AddAnswer(answers, resource, query); 432 AddAnswer(answers, info, query);
353 } 433 }
354 } 434 }
355 } 435 }
356 catch (OrthancException&) 436 catch (OrthancException&)
357 { 437 {