समय श्रृंखला डेटा कैसे संग्रहीत करें


22

मुझे लगता है कि मेरा मानना ​​है कि एक समय श्रृंखला डेटा सेट है (कृपया मुझे सही करें अगर मैं गलत हूं) जिसमें संबंधित मूल्यों का एक गुच्छा है।

एक उदाहरण एक कार मॉडलिंग और एक यात्रा के दौरान अपनी विभिन्न विशेषताओं को ट्रैक करना होगा। उदाहरण के लिए:

टाइमस्टैम्प | गति | की दूरी तय की | तापमान | आदि

इस डेटा को संग्रहीत करने का सबसे अच्छा तरीका क्या होगा ताकि एक वेब एप्लिकेशन अधिकतम समय पर सेट किए गए प्रत्येक डेटा को खोजने के लिए फ़ील्ड को क्वेरी कर सके?

मैंने डेटा डंप करने और परिणामों को कैशिंग करने के लिए एक भोली दृष्टिकोण शुरू किया ताकि उन्हें कभी भी संग्रहीत न करना पड़े। इसके साथ थोड़ा खेलने के बाद, हालांकि, ऐसा प्रतीत होता है कि यह समाधान मेमोरी की कमी के कारण दीर्घकालिक नहीं होगा और अगर कैश को साफ़ करना है, तो सभी डेटा को फिर से पार्स और फिर से कैश करना होगा।

इसके अलावा, यह मानते हुए कि डेटा को हर सेकंड 10+ घंटे के डेटा सेट की दुर्लभ संभावना के साथ ट्रैक किया जाता है, क्या यह आमतौर पर हर एन सेकंड का नमूना करके डेटा सेट को छोटा करने की सलाह दी जाती है?

जवाबों:


31

समय श्रृंखला डेटा संग्रहीत करने के लिए वास्तव में कोई 'सबसे अच्छा तरीका' नहीं है, और यह ईमानदारी से कई कारकों पर निर्भर करता है। हालांकि, मैं मुख्य रूप से दो कारकों पर ध्यान केंद्रित करने जा रहा हूं, उनके साथ:

(१) यह परियोजना कितनी गंभीर है कि यह स्कीमा को अनुकूलित करने के आपके प्रयास के योग्य है?

(२) आपके क्वेरी एक्सेस पैटर्न वास्तव में क्या होने जा रहे हैं?

उन सवालों को ध्यान में रखते हुए, आइए कुछ स्कीमा विकल्पों पर चर्चा करें।

फ्लैट टेबल

एक फ्लैट टेबल का उपयोग करने का विकल्प प्रश्न (1) से बहुत अधिक है , जहां अगर यह एक गंभीर या बड़े पैमाने पर परियोजना नहीं है, तो आपको स्कीमा के बारे में बहुत अधिक नहीं सोचना आसान होगा, और बस एक फ्लैट टेबल का उपयोग करें, जैसे:

CREATE flat_table(
  trip_id integer,
  tstamp timestamptz,
  speed float,
  distance float,
  temperature float,
  ,...);

ऐसे कई मामले नहीं हैं जहां मैं इस पाठ्यक्रम की सिफारिश करूंगा, केवल अगर यह एक छोटी परियोजना है जो आपके समय का बहुत वारंट नहीं करती है।

आयाम और तथ्य

इसलिए, यदि आपने प्रश्न (1) की बाधा को हटा दिया है , और आप अधिक प्रदर्शन स्कीमा चाहते हैं, तो यह विचार करने वाले पहले विकल्पों में से एक है। इसमें कुछ बुनियादी मानदंड शामिल हैं, लेकिन मापा 'तथ्य' मात्रा से 'आयामी' मात्राओं को निकालना।

अनिवार्य रूप से, आप यात्राओं के बारे में जानकारी दर्ज करने के लिए एक तालिका चाहते हैं,

CREATE trips(
  trip_id integer,
  other_info text);

और टाइमस्टैम्प रिकॉर्ड करने के लिए एक तालिका,

CREATE tstamps(
  tstamp_id integer,
  tstamp timestamptz);

और अंत में आपके सभी मापा तथ्य, आयाम तालिकाओं के विदेशी प्रमुख संदर्भों के साथ (जो meas_facts(trip_id)संदर्भ trips(trip_id)और meas_facts(tstamp_id)संदर्भ हैं tstamps(tstamp_id))

CREATE meas_facts(
  trip_id integer,
  tstamp_id integer,
  speed float,
  distance float,
  temperature float,
  ,...);

ऐसा नहीं लग सकता है कि यह सब पहले मददगार है, लेकिन अगर आपके पास उदाहरण के लिए हजारों समवर्ती यात्राएं हैं, तो वे सभी एक बार प्रति सेकंड, दूसरे पर माप ले सकते हैं। उस स्थिति में, आपको tstampsतालिका में केवल एक प्रविष्टि का उपयोग करने के बजाय, प्रत्येक यात्रा के लिए समय टिकट को फिर से रिकॉर्ड करना होगा ।

केस का उपयोग करें: अगर आप डेटा रिकॉर्ड कर रहे हैं तो कई समवर्ती यात्राएं होती हैं, तो यह मामला अच्छा होगा और आप सभी प्रकार के मापों तक पहुंचने में कोई आपत्ति नहीं करेंगे।

चूंकि Postgres पंक्तियों द्वारा पढ़ा जाता है, किसी भी समय आप चाहते थे, उदाहरण के लिए, speedकिसी दिए गए समय सीमा पर माप, आपको meas_factsतालिका से पूरी पंक्ति को पढ़ना चाहिए , जो निश्चित रूप से एक क्वेरी को धीमा कर देगा, हालांकि अगर डेटा सेट आप के साथ काम कर रहा है बहुत बड़ा नहीं है, तो आप भी अंतर नोटिस नहीं होगा।

अपने मापा तथ्यों को विभाजित करना

अंतिम खंड को थोड़ा और आगे बढ़ाने के लिए, आप अपने मापों को अलग-अलग तालिकाओं में तोड़ सकते हैं, जहां उदाहरण के लिए मैं गति और दूरी के लिए तालिकाओं को दिखाऊंगा:

CREATE speed_facts(
  trip_id integer,
  tstamp_id integer,
  speed float);

तथा

CREATE distance_facts(
  trip_id integer,
  tstamp_id integer,
  distance float);

बेशक, आप देख सकते हैं कि इसे अन्य मापों तक कैसे बढ़ाया जा सकता है।

केस का उपयोग करें: इसलिए यह आपको क्वेरी के लिए एक जबरदस्त गति नहीं देगा, शायद आपके गति प्रकार के बारे में क्वेरी करते समय गति में केवल एक रैखिक वृद्धि। ऐसा इसलिए है क्योंकि जब आप गति के बारे में जानकारी देखना चाहते हैं, तो आपको speed_factsतालिका की एक पंक्ति में मौजूद सभी अतिरिक्त, अनावश्यक जानकारी के बजाय केवल तालिका से पंक्तियों को पढ़ने की आवश्यकता है meas_facts

तो, आपको केवल एक माप प्रकार के बारे में डेटा के विशाल बल्बों को पढ़ने की आवश्यकता है, आपको कुछ लाभ मिल सकता है। एक दूसरे अंतराल पर आपके 10 घंटे के डेटा के प्रस्तावित मामले के साथ, आप केवल 36,000 पंक्तियाँ पढ़ रहे होंगे, इसलिए आपको ऐसा करने से वास्तव में कोई महत्वपूर्ण लाभ नहीं मिलेगा। हालाँकि, यदि आप 5,000 ट्रिप के लिए गति माप डेटा देख रहे थे, जो लगभग 10 घंटे थे, तो अब आप 180 मिलियन पंक्तियों को पढ़ रहे हैं। इस तरह की क्वेरी के लिए गति में एक रैखिक वृद्धि से कुछ लाभ मिल सकता है, इसलिए जब तक आपको एक समय में माप प्रकार के एक या दो तक पहुंचने की आवश्यकता होती है।

Arrays / HStore / & टोस्ट

आपको शायद इस हिस्से के बारे में चिंता करने की ज़रूरत नहीं है, लेकिन मुझे उन मामलों के बारे में पता है जहाँ यह मायने रखता है। यदि आपको बड़ी मात्रा में समय श्रृंखला डेटा का उपयोग करने की आवश्यकता है, और आप जानते हैं कि आपको एक विशाल ब्लॉक में सभी का उपयोग करने की आवश्यकता है, तो आप एक संरचना का उपयोग कर सकते हैं , जो टोस्ट टेबल्स का उपयोग करेगा , जो अनिवार्य रूप से आपके डेटा को बड़े, संपीड़ित में संग्रहीत करता है। खंडों। इससे डेटा तक त्वरित पहुंच होती है, जब तक कि आपका लक्ष्य सभी डेटा तक पहुंचना है।

एक उदाहरण कार्यान्वयन हो सकता है

CREATE uber_table(
  trip_id integer,
  tstart timestamptz,
  speed float[],
  distance float[],
  temperature float[],
  ,...);

इस तालिका tstartमें, सरणी में पहली प्रविष्टि के लिए समय टिकट संग्रहीत करेगा, और प्रत्येक बाद की प्रविष्टि अगले सेकंड के लिए एक पढ़ने का मूल्य होगा। इसके लिए आपको एप्लिकेशन सॉफ़्टवेयर के प्रत्येक सरणी मान के लिए प्रासंगिक समय स्टैम्प का प्रबंधन करना होगा।

एक और संभावना है

CREATE uber_table(
  trip_id integer,
  speed hstore,
  distance hstore,
  temperature hstore,
  ,...);

जहाँ आप अपने माप मानों को जोड़ते हैं (कुंजी, मान) (टाइमस्टैम्प, माप) के जोड़े।

केस का उपयोग करें: यह एक ऐसा कार्यान्वयन है जो संभवतः किसी ऐसे व्यक्ति के लिए बेहतर है जो PostgreSQL के साथ अधिक सहज है, और केवल तभी जब आप अपने एक्सेस पैटर्न के बारे में सुनिश्चित हों, जिसे बल्क एक्सेस पैटर्न की आवश्यकता हो।

निष्कर्ष?

वाह, यह मुझे अपेक्षा से अधिक लंबा हो गया, क्षमा करें। :)

अनिवार्य रूप से, कई विकल्प हैं, लेकिन आप संभवतः दूसरे या तीसरे का उपयोग करके अपने रुपये के लिए सबसे बड़ा धमाका करेंगे, क्योंकि वे अधिक सामान्य मामले में फिट होते हैं।

पुनश्च: आपके आरंभिक प्रश्न में निहित है कि आपके डेटा एकत्र किए जाने के बाद आप अपना डेटा लोड कर रहे होंगे। यदि आप अपने PostgreSQL उदाहरण में डेटा स्ट्रीम कर रहे हैं, तो आपको अपने डेटा अंतर्ग्रहण और क्वेरी कार्यभार दोनों को संभालने के लिए कुछ और काम करने की आवश्यकता होगी, लेकिन हम इसे दूसरी बार छोड़ देंगे। ;)


वाह, विस्तृत उत्तर के लिए धन्यवाद, क्रिस! मैं विकल्प 2 या 3 का उपयोग करने पर
गौर करूंगा

आप सौभाग्यशाली हों!
क्रिस

अगर मैं कर सकता तो वाह, मैं इस जवाब को 1000 बार वोट करूंगा। विस्तृत विवरण के लिए धन्यवाद।
kikocorreoso

1

इसका 2019 और यह सवाल एक अद्यतन जवाब के योग्य है।

  • दृष्टिकोण सबसे अच्छा है या नहीं कुछ ऐसा है जो मैं आपको बेंचमार्क और परीक्षण करने के लिए छोड़ दूँगा लेकिन यहां एक दृष्टिकोण है।
  • डेटाबेस एक्सटेंशन का उपयोग करें जिसे टाइमस्केड कहा जाता है
  • यह मानक PostgreSQL पर स्थापित एक एक्सटेंशन है और समय श्रृंखला को अच्छी तरह से संग्रहीत करते समय सामने आई कई समस्याओं को संभालता है

अपना उदाहरण लेते हुए, पहले PostgreSQL में एक साधारण तालिका बनाएं

चरण 1

CREATE TABLE IF NOT EXISTS trip (
    ts TIMESTAMPTZ NOT NULL PRIMARY KEY,
    speed REAL NOT NULL,
    distance REAL NOT NULL,
    temperature REAL NOT NULL
) 

चरण 2

  • इसे टाइमकेल्डब की दुनिया में हाइपरटेबल कहा जाता है ।
  • सरल शब्दों में, यह एक बड़ी तालिका है जिसे लगातार कुछ समय अंतराल की छोटी तालिकाओं में विभाजित किया जाता है, ऐसा दिन कहें जहां प्रत्येक मिनी तालिका को एक हिस्सा कहा जाता है।
  • यह मिनी टेबल स्पष्ट नहीं है जब आप प्रश्नों को चलाते हैं, हालांकि आप इसे अपने प्रश्नों में शामिल या बाहर कर सकते हैं

    Create create_hypertable ('ट्रिप', 'ts', chunk_time_interval => अंतराल '1 घंटा', if_not_exists => TRUE);

  • हमने जो कुछ ऊपर किया है वह हमारी यात्रा तालिका है, इसे हर घंटे मिनी चंक तालिकाओं में विभाजित करें स्तंभ 'ts' के आधार पर। यदि आप 10:00 से 10:59 के टाइमस्टैम्प को जोड़ते हैं, तो उन्हें 1 चंक में जोड़ा जाएगा, लेकिन 11:00 को एक नए चंक में डाला जाएगा और यह असीम रूप से आगे बढ़ेगा।

  • यदि आप डेटा को असीम रूप से संग्रहीत नहीं करना चाहते हैं, तो आप कह सकते हैं कि 3 महीने का उपयोग करने की तुलना में पुराने डीआरओपी चंक हो सकते हैं

    सेलेक्ट ड्रॉप_चंक्स (अंतराल '3 महीने', 'ट्रिप');

  • आप एक क्वेरी का उपयोग करके अब तक बनाई गई सभी विखंडू की सूची भी प्राप्त कर सकते हैं

    चुनिंदा chunk_table, table_bytes, index_bytes, कुल_bytes chunk_relation_size ('ट्रिप') से;

  • यह आपको आज तक बनाई गई सभी मिनी टेबल की एक सूची देगा और यदि आप इस सूची से चाहते हैं तो अंतिम मिनी टेबल पर एक क्वेरी चला सकते हैं

  • आप शामिल करने के लिए अपने प्रश्नों को ऑप्टिमाइज़ कर सकते हैं, विखंडू को बाहर कर सकते हैं या केवल अंतिम एन चंक्स और इतने पर काम कर सकते हैं

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