मैं निम्नलिखित कोड का उपयोग कर रहा हूं, और मैं कुछ अनुकूलन करने के लिए कुछ विचारों की तलाश कर रहा हूं।

पेलोड का विश्लेषण करें:

इनपुट: पेलोड जो JsObject है और नियमों की सूची है, प्रत्येक नियम की कई शर्तें हैं।

आउटपुट: MyReport सभी नियम जो इस विशिष्ट पेलोड पर सफल, लागू या विफल नहीं होते हैं।

सूची का आकार बहुत बड़ा हो सकता है, साथ ही प्रत्येक नियम में बड़ी मात्रा में शर्तें होती हैं।

मैं उस कोड को अनुकूलित करने के तरीके पर कुछ विचारों की तलाश में हूं, शायद आलसी संग्रह के साथ? दृश्य? धारा? टेलरेक? और क्यों - धन्यवाद!

साथ ही, ध्यान दें कि मेरे पास anaylzeMode है जो केवल एक नियम के सफल होने तक ही चल सकता है।

def analyzePayload(payload: JsObject, rules: List[Rule]): MyReport = {
    val analyzeMode = appConfig.analyzeMode
    val (succeed, notApplicable, failed) = rules.foldLeft((List[Rule](), List[Rule](), List[Rule]())) { case ( seed @ (succeedRules,notApplicableRules,failedRules), currRule) =>

      // Evaluate Single Rule
      def step(): (List[Rule], List[Rule], List[Rule]) = evalService.eval(currRule, payload) match {

        // If the result is succeed
        case EvalResult(true, _, _) => (currRule :: succeedRules, notApplicableRules, failedRules)

        // If the result is notApplicable 
        case EvalResult(_, missing @ _ :: _, _) => (succeedRules, currRule :: notApplicableRules, failedRules
        )

        // If the result is unmatched
        case EvalResult(_, _, unmatched @ _ :: _) => (succeedRules, notApplicableRules, currRule :: failedRules)
      }

      analyzeMode match {
        case UNTIL_FIRST_SUCCEED => if(succeedRules.isEmpty) step() else seed
        case UNTIL_FIRST_NOT_APPLICABLE => if(notApplicableRules.isEmpty) step() else seed
        case UNTIL_FIRST_FAILED => if(failedRules.isEmpty) step() else seed
        case DEFAULT => step()
        case _ => throw new IllegalArgumentException(s"Unknown mode = ${analyzeMode}")
      }
    }

    MyReport(succeed.reverse, notApplicable.reverse, failed.reverse)
  }

पहला संपादित करें: @Tim Advise से tailrec का उपयोग करने के लिए कोड बदल दिया, कोई अन्य सुझाव? या कोड को थोड़ा सुंदर बनाने के लिए कुछ सुझाव? साथ ही, मैं पूछना चाहता था कि पिछले कार्यान्वयन पर फोल्डलेफ्ट से पहले view का उपयोग करने में कोई अंतर है या नहीं। इसके अलावा शायद अन्य संग्रह जैसे ListBuffer या Vector का उपयोग करें

  def analyzePayload(payload: JsObject, actionRules: List[ActionRule]): MyReport = {
    val analyzeMode = appConfig.analyzeMode

    def isCompleted(succeed: List[Rule], notApplicable: List[Rule], failed: List[Rule]) = ((succeed, notApplicable, failed), analyzeMode) match {
      case (( _ :: _, _, _), UNTIL_FIRST_SUCCEED) | (( _,_ :: _, _), UNTIL_FIRST_NOT_APPLICABLE) | (( _, _, _ :: _), UNTIL_FIRST_FAILED) => true
      case (_, DEFAULT) => false
      case _ => throw new IllegalArgumentException(s"Unknown mode on analyzePayload with mode = ${analyzeMode}")
    }

    @tailrec
    def _analyzePayload(actionRules: List[ActionRule])(succeed: List[Rule], notApplicable: List[Rule], failed: List[Rule]): (List[Rule], List[Rule] ,List[Rule]) = actionRules match {
      case Nil | _ if isCompleted(succeed, notApplicable, failed) => (succeed, notApplicable, failed)
      case actionRule :: tail => actionRuleService.eval(actionRule, payload) match {
        // If the result is succeed
        case EvalResult(true, _, _) => _analyzePayload(tail)(actionRule :: succeed, notApplicable, failed)

        // If the result is notApplicable
        case EvalResult(_, missing @ _ :: _, _) => _analyzePayload(tail)(succeed, actionRule :: notApplicable, failed)

        // If the result is unmatched
        case EvalResult(_, _, unmatched @ _ :: _) => _analyzePayload(tail)(succeed, notApplicable, actionRule :: failed)
      }
    }

    val res = _analyzePayload(actionRules)(Nil,Nil,Nil)
    MyReport(res._1, res._2, res._3)
  }

संपादित करें 2: (प्रश्न)

  1. यदि कोई परिणाम ग्राहक को अग्रेषित किया जाएगा - view के रूप में ऐसा करने का कोई अर्थ नहीं है? चूंकि सभी डेटा का सही मूल्यांकन किया जाएगा?
  2. शायद मुझे इसके बजाय ParSeq का उपयोग करना चाहिए? या यह केवल धीमा होगा क्योंकि evalService.eval(...) का संचालन एक भारी ऑपरेशन नहीं है?
1
Zvi Mints 22 जिंदा 2021, 12:50

2 जवाब

सबसे बढ़िया उत्तर

दो स्पष्ट अनुकूलन:

foldLeft की तुलना में टेल-रिकर्सिव फ़ंक्शन रेटर का उपयोग करें ताकि कंपाइलर एक अनुकूलित लूप उत्पन्न कर सके और उपयुक्त नियम मिलते ही समाप्त हो जाए।

चूँकि analyzeMode स्थिर है, match को foldLeft के बाहर ले जाएं। या तो प्रत्येक मोड के लिए अलग कोड पथ हों, या समाप्ति की जांच के लिए लूप के अंदर उपयोग किए जाने वाले फ़ंक्शन का चयन करने के लिए analyzeMode का उपयोग करें।

2
Tim 22 जिंदा 2021, 14:10

कोड बल्कि ठीक है, फिर से देखने की मुख्य बात यह होगी कि evalService.eval जेसन ऑब्जेक्ट के एक ट्रैवर्सल में एकाधिक नियमों का मूल्यांकन करें, यह मानते हुए कि जेसन का आकार नगण्य नहीं है

-2
V-Lamp 22 जिंदा 2021, 15:10