2008-09-26 15 views
5

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

बस पायथन में फ़ंक्शन लिखना वास्तव में एक विकल्प नहीं है, क्योंकि कोई भी ऐसे सर्वर को स्थापित नहीं करना चाहता है जो रनटाइम पर मनमाने ढंग से पाइथन कोड को डाउनलोड और निष्पादित करता है।

मुझे इस लक्ष्य को प्राप्त करने के लिए डोमेन विशिष्ट भाषा को लागू करने के सबसे सरल तरीके से सुझावों की आवश्यकता है। भाषा को सरल अभिव्यक्ति मूल्यांकन के साथ-साथ टेबल इंडेक्स से पूछताछ करने और लौटाई पंक्तियों के माध्यम से पुनरावृत्त करने में सक्षम होना चाहिए। भाषा को लिखने और पढ़ने की आसानी इसे लागू करने में आसानी के लिए माध्यमिक है। मैं एक संपूर्ण क्वेरी ऑप्टिमाइज़र लिखना भी नहीं चाहूंगा, इसलिए कुछ ऐसा जो स्पष्ट रूप से निर्दिष्ट करता है कि क्वेरी करने के लिए कौन सी अनुक्रमणिका क्वेरी होगी।

इंटरफ़ेस जिसे इसके खिलाफ संकलित करना होगा, ऐप इंजन डेटास्टोर निर्यात के लिए क्षमताओं में समान होगा: आप तालिका पर किसी भी इंडेक्स पर अनुक्रमिक श्रेणियों के लिए क्वेरी कर सकते हैं (उदाहरण के लिए, कम से कम, सीमा से अधिक और समानता प्रश्न), फिर किसी भी बुलियन अभिव्यक्ति द्वारा लौटाई गई पंक्ति फ़िल्टर करें। आप एक साथ कई स्वतंत्र परिणाम सेट को भी जोड़ सकते हैं।

मुझे एहसास है कि यह प्रश्न बहुत कुछ लगता है जैसे मैं SQL के लिए पूछ रहा हूं। हालांकि, मैं यह नहीं चाहता हूं कि इस डेटा का समर्थन करने वाले डेटास्टोर एक रिलेशनल डेटाबेस हो, और मैं स्वयं को एसक्यूएल को फिर से लागू करने की कोशिश करने का ओवरहेड नहीं चाहता हूं। मैं एक ज्ञात स्कीमा के साथ केवल एक ही टेबल से निपट रहा हूं। अंत में, कोई भी शामिल होने की आवश्यकता नहीं होगी। कुछ आसान बहुत बेहतर होगा।

संपादित करें: कुछ गलत धारणाओं को साफ़ करने के लिए विस्तारित विवरण।

+0

क्या यह ऐप इंजन में जीक्यूएल लागू करने के लिए था? : पी – wTyeRogers

उत्तर

4

में बनाए गए एक डीएसएल अजगर से व्याख्या की जा करने के लिए बिल्डिंग का एक अच्छा उदाहरण है।

चरण 1. रन-टाइम कक्षाओं और वस्तुओं का निर्माण करें। इन कक्षाओं में सभी कर्सर लूप और एसक्यूएल कथन होंगे और उन सभी एल्गोरिदमिक प्रसंस्करण उनके तरीकों से दूर हो जाएंगे। इन कक्षाओं के निर्माण के लिए आप Command और Strategy डिज़ाइन पैटर्न का भारी उपयोग करेंगे। अधिकांश चीजें कमांड हैं, विकल्प और विकल्प प्लग-इन रणनीतियों हैं। Apache Ant's Task API के लिए डिज़ाइन को देखें - यह एक अच्छा उदाहरण है।

चरण 2. मान्य करें कि ऑब्जेक्ट्स की यह प्रणाली वास्तव में काम करती है। सुनिश्चित करें कि डिज़ाइन सरल और पूर्ण है। आप परीक्षण कमांड और रणनीति ऑब्जेक्ट्स का निर्माण करेंगे, और उसके बाद शीर्ष-स्तरीय कमांड ऑब्जेक्ट निष्पादित करेंगे। कमांड ऑब्जेक्ट्स काम करेगा।

इस बिंदु पर आप बड़े पैमाने पर कर रहे हैं। आपका रन-टाइम उपर्युक्त डोमेन से बनाए गए ऑब्जेक्ट्स की कॉन्फ़िगरेशन है। [यह उतना आसान नहीं है जितना लगता है। इसके लिए कक्षाओं के एक सेट को परिभाषित करने के लिए कुछ देखभाल की आवश्यकता होती है जिसे तत्काल किया जा सकता है और फिर अपने आवेदन के काम को करने के लिए "स्वयं के बीच बात करें"।

ध्यान दें कि आपके पास क्या होगा, घोषणाओं से अधिक कुछ नहीं चाहिए। प्रक्रियात्मक के साथ क्या गलत है? एक आप प्रक्रियात्मक तत्वों के साथ एक डीएसएल लिखना शुरू करते हैं, आप पाते हैं कि जब तक आप पाइथन को विभिन्न वाक्यविन्यास के साथ नहीं लिखते हैं, तब तक आपको अधिक से अधिक विशेषताओं की आवश्यकता होती है। अच्छा नही।

आगे, प्रक्रियात्मक भाषा दुभाषियों को लिखना मुश्किल है। निष्पादन का राज्य, और संदर्भों का दायरा प्रबंधन करने में मुश्किल है।

आप देशी पायथन का उपयोग कर सकते हैं - और "सैंडबॉक्स से बाहर निकलने" के बारे में चिंता करना बंद कर दें। दरअसल, इस तरह आप अपनी ऑब्जेक्ट्स बनाने के लिए एक छोटी पायथन स्क्रिप्ट का उपयोग करके इकाई को सबकुछ परीक्षण करेंगे। पाइथन डीएसएल होगा।

["लेकिन प्रतीक्षा करें", आप कहते हैं, "अगर मैं बस पाइथन का उपयोग करता हूं क्योंकि डीएसएल लोग मनमानी चीजें निष्पादित कर सकते हैं।" PYTHONPATH पर क्या है, और sys.path पर निर्भर करता है। क्या उपलब्ध है इसे नियंत्रित करने के तरीकों के लिए site मॉड्यूल देखें।]

एक घोषणात्मक डीएसएल सबसे सरल है। यह प्रतिनिधित्व में पूरी तरह से एक अभ्यास है। पाइथन का एक ब्लॉक जो केवल कुछ चर के मान सेट करता है वह अच्छा है। Django का उपयोग करता है।

आप वस्तुओं की अपनी रन-टाइम कॉन्फ़िगरेशन का प्रतिनिधित्व करने के लिए ConfigParser भाषा का उपयोग कर सकते हैं।

आप वस्तुओं की अपनी रन-टाइम कॉन्फ़िगरेशन का प्रतिनिधित्व करने के लिए JSON या YAML का उपयोग कर सकते हैं। तैयार किए गए पार्सर्स पूरी तरह से उपलब्ध हैं।

आप एक्सएमएल का भी उपयोग कर सकते हैं। डिजाइन और पार्स करना मुश्किल है, लेकिन यह ठीक काम करता है। लोग इसे प्यार करते हैं। इस तरह चींटी और मेवेन (और कई अन्य टूल्स) प्रक्रियाओं का वर्णन करने के लिए घोषणात्मक वाक्यविन्यास का उपयोग करते हैं। मैं इसकी सिफारिश नहीं करता, क्योंकि यह गर्दन में एक शब्दशः दर्द है। मैं बस पायथन का उपयोग करने की सलाह देते हैं।

या, आप गहरे अंत से बाहर जा सकते हैं और अपना स्वयं का वाक्यविन्यास आविष्कार कर सकते हैं और अपना खुद का पार्सर लिख सकते हैं।

+0

सभी अच्छे सुझाव, लेकिन मैं अभी भी एक प्रभावी वाक्यविन्यास या प्रारूप का सुझाव ढूंढ रहा हूं। प्रक्रियात्मक या घोषणात्मक? कर्सर को कैसे संभालना सबसे अच्छा है? आदि –

+0

इन दो बिंदुओं का जवाब देने के लिए संपादित किया गया। घोषणात्मक। एसक्यूएल कर्सर लूप कोर क्लास में हैं। –

0

ऐसी भाषा क्यों न बनाएं जब यह "संकलित" हो, तो यह एसक्यूएल उत्पन्न करता है या आपके डेटास्टोर को जो भी क्वेरी भाषा चाहिए?

आप मूल रूप से अपनी दृढ़ता परत पर एक अमूर्त बनायेंगे।

+0

सर्वर आर्किटेक्चर कई संभावित डेटास्टोर कार्यान्वयन के लिए अनुमति देता है। सबसे आसान संभव एक साधारण इन-मेमोरी टेबल है, इसलिए क्वेरी डेटा मेरी डेटास्टोर की आवश्यकता है, ठीक है, पायथन। –

0

आपने पायथन का उल्लेख किया है। पायथन का उपयोग क्यों नहीं करें? अगर कोई आपके डीएसएल में एक अभिव्यक्ति "टाइप" कर सकता है, तो वे पाइथन में टाइप कर सकते हैं।

आपको अभिव्यक्ति की संरचना पर कुछ नियमों की आवश्यकता होगी, लेकिन यह कुछ नया लागू करने से बहुत आसान है।

+0

मैंने पहले ही कहा है क्यों: कोई भी ऐसे सर्वर को चलाने के लिए नहीं जा रहा है जो रनटाइम पर मनमाने ढंग से कोड डाउनलोड और निष्पादित करता है। और एक पार्सर जो यह सुनिश्चित करने के लिए पाइथन को पूरी तरह से पर्याप्त जांच सकता है कि यह कुछ भी दुर्भावनापूर्ण नहीं कर रहा है, वैसे भी एक उचित डीएसएल लिखने के रूप में जटिल होने की संभावना है। –

+0

लेकिन यह एक सुरक्षा समस्या है जिसे प्रबंधित किया जा सकता है। उदाहरण के लिए, आप डीबीए रनटाइम पर मनमानी कोड डाउनलोड कर सकते हैं। इस प्रक्रिया को कितना दुर्लभ लगता है, इस बात पर विचार करना कि किसी को काम करने पर भरोसा नहीं किया जा सकता है। –

+0

संपूर्ण बिंदु यह है कि इसे प्रत्येक सर्वर व्यवस्थापक से मैन्युअल हस्तक्षेप की आवश्यकता नहीं हो सकती है। मुझे एक डीएसएल चाहिए जो इस फैशन में पूछताछ/फ़िल्टर करने में सक्षम है, लेकिन सर्वर प्रशासक अपने हस्तक्षेप या पर्यवेक्षण के बिना अद्यतन होने पर भरोसा कर सकते हैं। –

0

आपने कहा कि कोई भी ऐसे सर्वर को स्थापित नहीं करना चाहता है जो रनटाइम पर मनमाने ढंग से कोड डाउनलोड और निष्पादित करता है। हालांकि, यह वही है जो आपका डीएसएल करेगा (अंत में) तो संभवतया इसमें कोई अंतर नहीं है। जब तक आप डेटा के साथ कुछ विशिष्ट नहीं कर रहे हैं तो मुझे नहीं लगता कि एक डीएसएल आपको इतना खरीद लेगा और यह उन उपयोगकर्ताओं को निराश करेगा जो पहले से ही एसक्यूएल में हैं। उस कार्य के आकार को कम मत समझें जिसे आप ले जा रहे हैं।

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

गणितीय अभिव्यक्तियों के लिए व्याकरण पर बहुत सारे शैक्षिक ग्रंथ हैं जिन्हें आप नेट पर संदर्भित कर सकते हैं, जो काफी सीधे है।आपके पास एक पार्सर जेनरेटर टूल हो सकता है जैसे एएनटीएलआर या वाईएसी आप पार्सर उत्पन्न करने में मदद के लिए उपयोग कर सकते हैं (या लिस्प/स्कीम जैसी भाषा का उपयोग करें और दो से शादी करें)। एक उचित एसक्यूएल व्याकरण के साथ आना आसान नहीं होगा। लेकिन गूगल 'बीएनएफ एसक्यूएल' और देखें कि आप किसके साथ आते हैं।

शुभकामनाएं।

+0

हां, यह 'मनमानी' कोड डाउनलोड करेगा, लेकिन जब यह इस डीएसएल के संदर्भ में व्यक्त किया जाता है, तो यह अधिक नहीं कर सकता है। मनमानी पायथन कोड और मनमाने ढंग से फ़िल्टर अभिव्यक्ति (या समान) के बीच अंतर की दुनिया है। –

1

मुझे लगता है कि हमें यहां कुछ और जानकारी की आवश्यकता होगी। मुझे बताएं कि निम्न में से कोई भी गलत धारणाओं पर आधारित है।

सबसे पहले, जैसा कि आपने स्वयं को इंगित किया है, पहले से ही मनमानी तालिकाओं से पंक्तियों का चयन करने के लिए एक डीएसएल मौजूद है - इसे "एसक्यूएल" कहा जाता है। चूंकि आप एसक्यूएल को फिर से शुरू नहीं करना चाहते हैं, इसलिए मुझे लगता है कि आपको केवल एक ही प्रारूप से एक निश्चित प्रारूप के साथ क्वेरी करने की आवश्यकता है।

यदि ऐसा है, तो आपको शायद एक डीएसएल लागू करने की आवश्यकता नहीं है (हालांकि यह निश्चित रूप से जाने का एक तरीका है); फ़िल्टर ऑब्जेक्ट बनाने के लिए, यदि आप ऑब्जेक्ट ओरिएंटेशन में उपयोग किया जाता है, तो यह आसान हो सकता है।

अधिक विशेष रूप से, एक "फ़िल्टर" संग्रह जिसमें एक या अधिक चयनक्रिटेशन ऑब्जेक्ट्स होंगे। आप इनमें से एक या अधिक आधार वर्गों के चयन के लिए कार्यान्वित कर सकते हैं जो कि चयन के प्रकार (रेंज, लेसन, एक्सएक्टमैच, लाइक इत्यादि) का प्रतिनिधित्व करते हैं। इन बेस क्लासों के स्थान पर होने के बाद, आप कॉलम-विशिष्ट विरासत वाले संस्करण बना सकते हैं जो उस कॉलम के लिए उपयुक्त हैं । अंत में, उन प्रश्नों की जटिलता के आधार पर जिन्हें आप समर्थन देना चाहते हैं, आप विभिन्न मानदंडों के बीच AND और OR को संभालने के लिए किसी प्रकार के संयोजी गोंद को लागू करना चाहते हैं।

यदि आपको ऐसा लगता है, तो आप संग्रह को लोड करने के लिए एक सरल जीयूआई बना सकते हैं; यदि आपके पास दिमाग में कुछ और नहीं है, तो मैं Excel में फ़िल्टरिंग को मॉडल के रूप में देखता हूं।

अंत में, इस संग्रह की सामग्री को संबंधित एसक्यूएल में परिवर्तित करने के लिए छोटा होना चाहिए, और डेटाबेस को पास करना चाहिए।

हालांकि: यदि आप सादगी के बाद क्या हैं, और आपके उपयोगकर्ता एसक्यूएल समझते हैं, तो आप उन्हें केवल WHERE क्लॉज की सामग्री में टाइप करने के लिए कह सकते हैं, और प्रोग्रामेटिक रूप से शेष क्वेरी का निर्माण कर सकते हैं। सुरक्षा परिप्रेक्ष्य से, यदि आपके कोड में चयनित कॉलम पर नियंत्रण है और FROM खंड, और आपकी डेटाबेस अनुमतियां ठीक से सेट की गई हैं, और आप उपयोगकर्ताओं से आने वाली स्ट्रिंग पर कुछ सैनिटी जांच करते हैं, तो यह अपेक्षाकृत सुरक्षित विकल्प होगा।

+0

अधिकतर ध्वनि, लेकिन मुझे फ़िल्टर संग्रह आदि निर्दिष्ट करने के लिए अभी भी कुछ तरीका चाहिए। ध्यान रखें कि यहां लक्ष्य मेरे लिए एक अद्यतन फ़ंक्शन निर्दिष्ट करने में सक्षम है और यह क्लस्टर में सभी सर्वरों के लिए प्रचारित है। –

0

यह वास्तव में एसक्यूएल की तरह लगता है, लेकिन शायद SQLite का उपयोग करने का प्रयास करना उचित है यदि आप इसे सरल रखना चाहते हैं?

1

मैं एक डीएसएल चाहते हैं "कोई भी एक सर्वर है कि डाउनलोड और रनटाइम पर मनमाने ढंग से अजगर कोड निष्पादित करता है स्थापित करना चाहते करने जा रहा है" "एक डोमेन विशिष्ट भाषा को लागू" लेकिन मैं अजगर नहीं करना चाहते डीएसएल होने के लिए। ठीक है। आप इस डीएसएल को कैसे निष्पादित करेंगे? क्या रनटाइम स्वीकार्य है यदि पायथन नहीं है?

क्या होगा यदि मेरे पास एक सी प्रोग्राम है जो पाइथन दुभाषिया को एम्बेड करने के लिए होता है? क्या यह स्वीकार्य है?

और - यदि पाइथन स्वीकार्य रनटाइम नहीं है - इसमें पाइथन टैग क्यों है?

+0

मैं पाइथन में एक दुभाषिया लिखकर डीएसएल निष्पादित करूंगा। यही कारण है कि इसमें पाइथन टैग है। इस मामले में एक डीएसएल का उपयोग करने का पूरा बिंदु यह है कि यह सैंडबॉक्स से बाहर निकलने के लिए लिखे गए कोड को अनुमति नहीं देगा और पूरी तरह से सिस्टम को प्रभावित करेगा। –

0

ऐसा लगता है जैसे आप एक व्याकरण बनाना चाहते हैं जो डीएसएल नहीं है। मैं ANTLR पर देखता हूं जो आपको एक विशिष्ट पार्सर बनाने की अनुमति देगा जो पाठ की व्याख्या करेगा और विशिष्ट आदेशों में अनुवाद करेगा। एएनटीएलआर पाइथन, एसक्यूएल, जावा, सी ++, सी, सी # आदि के लिए पुस्तकालय प्रदान करता है।

इसके अलावा, यहाँ एक ANTLR calculation engine सी #

+0

यह सिर्फ एक व्याकरण से अधिक है - मुझे इसे सिर्फ पार्स करने की आवश्यकता नहीं है, लेकिन इसे निष्पादित करने की आवश्यकता है, जो इसे एक पूर्ण डीएसएल बनाता है। 'गणना इंजन' के उदाहरण में पार्सर में एम्बेडेड निष्पादन कोड है। –

0

एक संदर्भ मुक्त व्याकरण आमतौर पर संरचना जैसे पेड़ और कार्यात्मक कार्यक्रमों में संरचना जैसे वृक्ष होते हैं। मैं दावा नहीं करता कि निम्नलिखित सभी आपकी समस्याओं का समाधान करेंगे, लेकिन यदि आप सुनिश्चित हैं कि आप SQLite3 जैसे कुछ उपयोग नहीं करना चाहते हैं तो यह दिशा में एक अच्छा कदम है।

from functools import partial 
def select_keys(keys, from_): 
    return ({k : fun(v, row) for k, (v, fun) in keys.items()} 
      for row in from_) 

def select_where(from_, where): 
    return (row for row in from_ 
      if where(row)) 

def default_keys_transform(keys, transform=lambda v, row: row[v]): 
    return {k : (k, transform) for k in keys} 

def select(keys=None, from_=None, where=None): 
    """ 
    SELECT v1 AS k1, 2*v2 AS k2 FROM table WHERE v1 = a AND v2 >= b OR v3 = c 

    translates to 

    select(dict(k1=(v1, lambda v1, r: r[v1]), k2=(v2, lambda v2, r: 2*r[v2]) 
     , from_=table 
     , where= lambda r : r[v1] = a and r[v2] >= b or r[v3] = c) 
    """ 
    assert from_ is not None 
    idfunc = lambda k, t : t 
    select_k = idfunc if keys is None else select_keys 
    if isinstance(keys, list): 
     keys = default_keys_transform(keys) 
    idfunc = lambda t, w : t 
    select_w = idfunc if where is None else select_where 
    return select_k(keys, select_w(from_, where)) 

आप कैसे सुनिश्चित करते हैं कि आप उपयोगकर्ताओं को मनमाने ढंग से कोड निष्पादित करने की क्षमता नहीं दे रहे हैं। यह ढांचा सभी संभावित कार्यों को स्वीकार करता है। खैर, आप सुरक्षा के लिए उस पर एक रैपर सही कर सकते हैं जो स्वीकार्य फ़ंक्शन ऑब्जेक्ट्स की एक निश्चित सूची का खुलासा करता है।

ALLOWED_FUNCS = [ operator.mul, operator.add, ...] # List of allowed funcs 

def select_secure(keys=None, from_=None, where=None): 
    if keys is not None and isinstance(keys, dict): 
     for v, fun keys.values: 
      assert fun in ALLOWED_FUNCS 
    if where is not None: 
     assert_composition_of_allowed_funcs(where, ALLOWED_FUNCS) 
    return select(keys=keys, from_=from_, where=where) 

assert_composition_of_allowed_funcs कैसे लिखें। ऐसा करना बहुत मुश्किल है कि यह अजगर में है लेकिन लिस्प में आसान है। आइए मान लें कि प्रारूपों की एक सूची कहां है, जैसे कि where=(operator.add, (operator.getitem, row, v1), 2) या where=(operator.mul, (operator.add, (opreator.getitem, row, v2), 2), 3) जैसे होंठ में मूल्यांकन किया जाना चाहिए।

यह apply_lisp फ़ंक्शन लिखना संभव बनाता है जो सुनिश्चित करता है कि जहां फ़ंक्शन केवल ALLOWED_FUNCS या फ्लोट, int, str जैसे स्थिरांक से बना है।

def apply_lisp(where, rowsym, rowval, ALLOWED_FUNCS): 
    assert where[0] in ALLOWED_FUNCS 
    return apply(where[0], 
      [ (apply_lisp(w, rowsym, rowval, ALLOWED_FUNCS) 
      if isinstance(w, tuple) 
      else rowval if w is rowsym 
      else w if isinstance(w, (float, int, str)) 
      else None) for w in where[1:] ]) 

इसके अलावा, आपको सटीक प्रकार की जांच करने की भी आवश्यकता होगी, क्योंकि आप नहीं चाहते कि आपके प्रकार ओवरराइड हो जाएं। तो isinstance का उपयोग न करें, type in (float, int, str) का उपयोग करें।

Greenspun की प्रोग्रामिंग की दसवीं नियम:: ओह लड़का हम में चलाने की है किसी भी पर्याप्त जटिल सी या फोरट्रान कार्यक्रम एक तदर्थ अनौपचारिक रूप से निर्दिष्ट बग ग्रस्त धीमी गति से कॉमन लिस्प के आधे के कार्यान्वयन में शामिल है।

संबंधित मुद्दे