ElasticSearch मल्टी लेवल पैरेंट-चाइल्ड एग्रीगेशन


79

मेरे पास 3 स्तरों में माता-पिता / बच्चे की संरचना है। हम कहते हैं:

कंपनी -> कर्मचारी -> उपलब्धता

चूंकि उपलब्धता (और कर्मचारी भी) अक्सर यहां अपडेट की जाती है, मैं नेस्टेड के खिलाफ माता-पिता / बच्चे की संरचना का उपयोग करता हूं। और खोज फ़ंक्शन ठीक काम करता है (सभी दस्तावेज़ सही शार्क में)।

अब मैं उन परिणामों को क्रमबद्ध करना चाहता हूं। कंपनी (प्रथम स्तर) के मेटा डेटा द्वारा उन्हें क्रमबद्ध करना आसान है। लेकिन मुझे तीसरे स्तर (उपलब्धता) के हिसाब से भी छांटना होगा।

मैं उन कंपनियों की सूची चाहता हूं जो निम्न प्रकार से हैं:

  • स्थान से दूरी ASC दी
  • रेटिंग DESC
  • जल्द ही उपलब्धता ए.एस.सी.

उदाहरण के लिए:

कंपनी A 5 मील दूर है, रेटिंग 4 है और जल्द ही उनका एक कर्मचारी 20 घंटे में उपलब्ध है। कंपनी B 5 मील दूर भी है, रेटिंग 4 भी है लेकिन जल्द ही उनका एक कर्मचारी 5 घंटे में उपलब्ध है।

इसलिए सॉर्ट परिणाम बी, ए होना चाहिए।

मैं इस डेटा में से प्रत्येक के लिए विशेष वजन जोड़ना चाहूंगा, इसलिए मैंने एकत्रीकरण लिखना शुरू कर दिया, जिसे मैं बाद में अपनी custom_score स्क्रिप्ट में उपयोग कर सकता था।

सूचकांक बनाने, डेटा आयात करने और

अब खोज करने के लिए पूर्ण जिस्ट , मैं एक क्वेरी लिखने में कामयाब रहा हूं जो वास्तव में वापस परिणाम देता है, लेकिन उपलब्धता एकत्रीकरण बाल्टी खाली है। हालाँकि, मैं परिणाम भी वापस संरचित कर रहा हूँ, मैं उन्हें समतल करना चाहूँगा।

वर्तमान में मैं वापस मिल गया:

कंपनी आईडीएस -> कर्मचारी आईडीएस -> पहली उपलब्धता

मैं चाहता हूं कि एकत्रीकरण हो:

कंपनी आईडीएस -> पहली उपलब्धता

इस तरह मैं custom_scoreस्कोर की गणना करने और उन्हें ठीक से सॉर्ट करने के लिए अपनी स्क्रिप्ट करने में सक्षम हूं ।

अधिक सरलीकृत प्रश्न:
बहु स्तरीय (भव्य) बच्चों द्वारा किसी प्रकार को कैसे क्रमबद्ध / एकत्र किया जा सकता है और परिणाम को संभवत: समतल कर सकता है।


क्या आप अपनी मैपिंग और कुछ उदाहरण डॉक्स (वंशजों के साथ) जोड़ सकते हैं? यह देखना कठिन है कि नकली डॉक्स का आविष्कार कैसे किया जाए जो आपके सिस्टम के पर्याप्त परीक्षण की अनुमति देता है।
स्लोअन एहरेंस

हे स्लोन - मैंने मैपिंग और नमूना परिणाम जोड़ दिए हैं। मैंने आसानी से समझने के लिए इसे छीन लिया है। फुल स्टैक में बहुत अधिक डेटा है :) धन्यवाद!
पीट माइनस

मेरा यहाँ भी यही सवाल था । यद्यपि मैं शायद कम प्रदर्शन करता हूं, मैं उन सभी परिणामों के लिए अनुरोध करता हूं जिनमें डिफ़ॉल्ट प्रकार का डॉकाउंट है। मैंने तब अपना पुनरावर्ती चपटा, छांटना और सीमित किया, जो आदर्श नहीं था।
मैट त्रयणम '

1
मैंने आपकी जिह्वा पर अमल किया है, लेकिन खोजते समय मुझे त्रुटि 500 ​​मिली Query Failed [Failed to execute main query]]; nested: NullPointerException;। क्या आप अपने स्थानीय परिवेश पर अपनी पकड़ बना सकते हैं और यह सुनिश्चित कर सकते हैं कि यह ठीक है? धन्यवाद!
वैल

अपने परिणामों के लिए समीकरण क्यों न बनाएं। आपका डेटा फ़ज़ी नहीं है! आप हर क्वेरी को एकत्र करते हैं? । एग्रीगेट इनपुट एक्शन है, क्वेरी या आउटपुट नहीं। एक सवाल "आप इस परिणाम की जांच कैसे करते हैं यह सच है (सही)?"
dsgdfg

जवाबों:


3

आपको ऐसा करने के लिए एकत्रीकरण की आवश्यकता नहीं है:

ये क्रमबद्ध मापदंड हैं:

  1. दूरी ASC (company.location)
  2. रेटिंग DESC (company.rating_value)
  3. सबसे पहले भविष्य की उपलब्धता ASC (company.employee.avucation.start)

यदि आप # 3 को अनदेखा करते हैं, तो आप इस तरह से अपेक्षाकृत सरल कंपनी क्वेरी चला सकते हैं :

GET /companies/company/_search
{
 "query": { "match_all" : {} },
 "sort": {
    "_script": {
        "params": {
            "lat": 51.5186,
            "lon": -0.1347
        },
        "lang": "groovy",
        "type": "number",
        "order": "asc",
        "script": "doc['location'].distanceInMiles(lat,lon)"
    },
    "rating_value": { "order": "desc" }
  }
}

# 3 मुश्किल है क्योंकि आपको नीचे पहुंचने और अनुरोध के समय के लिए प्रत्येक कंपनी के लिए उपलब्धता ( कंपनी> कर्मचारी> उपलब्धता ) खोजने की आवश्यकता है और उस अवधि को तीसरे प्रकार की कसौटी के रूप में उपयोग करें ।

हम function_scoreअनुरोध समय और हिट में प्रत्येक उपलब्धता के बीच समय अंतर लेने के लिए पोते के स्तर पर एक क्वेरी का उपयोग करने जा रहे हैं _score। (फिर हम _scoreतीसरे प्रकार की कसौटी के रूप में उपयोग करेंगे)।

पोते तक पहुँचने के लिए हमें एक has_childक्वेरी के अंदर एक has_childक्वेरी का उपयोग करने की आवश्यकता है ।

प्रत्येक कंपनी के लिए हम जल्द से जल्द उपलब्ध कर्मचारी चाहते हैं (और निश्चित रूप से उनकी निकटतम उपलब्धता)। Elasticsearch 2.0 हमें एक दे देंगे "score_mode": "min"क्योंकि हम तक सीमित किया गया इस तरह के मामलों के लिए है, लेकिन अब के लिए, "score_mode": "max"हम बना देंगे पोता _scoreहो पारस्परिक समय अंतर का।

          "function_score": {
            "filter": { 
              "range": { 
                "start": {
                  "gt": "2014-12-22T10:34:18+01:00"
                } 
              }
            },
            "functions": [
              {
                "script_score": {
                  "lang": "groovy",
                  "params": {
                      "requested": "2014-12-22T10:34:18+01:00",
                      "millisPerHour": 3600000
                   },
                  "script": "1 / ((doc['availability.start'].value - new DateTime(requested).getMillis()) / millisPerHour)"
                }
              }
            ]
          }

तो अब _scoreप्रत्येक पोते के लिए ( उपलब्धता ) होगा 1 / number-of-hours-until-available(ताकि हम कर्मचारी के प्रति उपलब्ध होने तक अधिकतम पारस्परिक समय का उपयोग कर सकें , और अधिकतम प्रतिपूर्ति (ly?) उपलब्ध कर्मचारी प्रति कंपनी)।

यह सब एक साथ रखें, हम क्वेरी करने के लिए जारी कंपनी लेकिन उपयोग कंपनी> कर्मचारी> की उपलब्धता उत्पन्न करने के लिए _scoreके रूप में उपयोग करने के लिए # 3 तरह कसौटी:

GET /companies/company/_search
{
 "query": { 
    "has_child" : {
        "type" : "employee",
        "score_mode" : "max",
        "query": {
          "has_child" : {
            "type" : "availability",
            "score_mode" : "max",
            "query": {
              "function_score": {
                "filter": { 
                  "range": { 
                    "start": {
                      "gt": "2014-12-22T10:34:18+01:00"
                    } 
                  }
                },
                "functions": [
                  {
                    "script_score": {
                      "lang": "groovy",
                      "params": {
                          "requested": "2014-12-22T10:34:18+01:00",
                          "millisPerHour": 3600000
                       },
                      "script": "1/((doc['availability.start'].value - new DateTime(requested).getMillis()) / millisPerHour)"
                    }
                  }
                ]
              }
            }
          }
        }
    }
 },
 "sort": {
  "_script": {
    "params": {
        "lat": 51.5186,
        "lon": -0.1347
    },
    "lang": "groovy",
    "type": "number",
    "order": "asc",
    "script": "doc['location'].distanceInMiles(lat,lon)"
  },
  "rating_value": { "order": "desc" },
  "_score": { "order": "asc" }
 }
}

आप एक का उपयोग कर थोड़ा बेहतर प्रदर्शन मिल सकता है रैखिक क्षय समारोह उत्पन्न करने के लिए एक स्क्रिप्ट के बजाय _scoreसे समय-जब तक उपलब्ध
पीटर डिक्सन-मूसा

डिफ़ॉल्ट रूप से एलेस्टिक्स खोज ने डायनेमिक स्क्रिप्टिंग को अक्षम कर दिया है। अनुक्रमित लिपियों का उपयोग करना बेहतर है। यहाँ देखें: elastic.co/blog/...
schellingerht

पीट माइनस: क्या आप यह काम कर पा रहे थे? मुझे पता है कि यह एक पुराना सवाल है, हालांकि आपके समाधान में बहुत सारे लोग रुचि रखते हैं।
पीटर डिक्सन-मूसा

पीटर डिक्सन-मूसा: आखिरकार मैंने हार मान ली और दो प्रश्न लिखे - पहले कंपनी / कर्मचारी द्वारा खोज करना और फिर उपलब्धता के माध्यम से शीर्ष 100 कंपनियों की खोज करना और फिर विलय करना। क्यों? केवल ES में इसे बनाने में बहुत अधिक समय / प्रयास लग रहा था। खोज के लिए खर्च किया गया समय स्वीकार्य है।
पीट माइनस

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.