एन-ग्राम डेटा संग्रहीत करना


12

मैं एन- मॉर्ग डेटा संग्रहीत करने के विषय पर थोड़ा मंथन करने की उम्मीद कर रहा था । अपनी परियोजना में, मैं भाषाई समस्याओं को हल करने की कोशिश कर रहा हूं, जहां मुझे सभी ( n -1) डेटा आइटम पता हैं और सभी लागू n -grams पर रैखिक प्रक्षेप का उपयोग करके सांख्यिकीय रूप से मेरे n का अनुमान लगाना चाहते हैं। (हां, एक टैगर है जो अपने शब्द के अनुसार शब्दों को टैग करता है और एक प्रत्यय वृक्ष है जो अज्ञात शब्दों के लिए शब्द प्रकार का अनुमान लगाने की कोशिश करता है; यहां चर्चा की गई एन -ग्राम घटक को महत्वता को हल करने के साथ सौंपा जाएगा।)

मेरा प्रारंभिक दृष्टिकोण केवल संबंधित SQL डेटाबेस में सभी देखे गए एन -ग्राम ( n = 1..3, यानी मोनोग्राम, बिग्राम, ट्रायग्राम) डेटा को स्टोर करना होगा और इसे एक दिन में कॉल करना होगा। लेकिन मेरी परियोजना की आवश्यकताओं में अन्य वेक्टर लंबाई ( एन ) को शामिल करने के लिए बदल सकता है , और मैं अपने आवेदन को बहुत काम के बिना 4-ग्राम के लिए अनुकूल करना चाहूंगा (स्कीमा को अपडेट करना, एप्लिकेशन कोड अपडेट करना, आदि); आदर्श रूप से, मैं बस अपने आवेदन को 4-ग्राम के साथ काम करने के लिए कहूंगा, बिना कोड को बदलने के (या बिल्कुल) और उसके डेटा को किसी दिए गए डेटा स्रोत से प्रशिक्षित करना होगा।

सभी आवश्यकताओं को पूरा करने के लिए:

  • N -ग्राम डेटा (प्रारंभ में n = {1, 2, 3} के लिए संग्रहीत करने की क्षमता
  • किस प्रकार के एन -ग्राम का उपयोग किया जाना चाहिए (एप्लिकेशन रन के बीच) बदलने की क्षमता
  • (N-) ट्रेन एन -ग्राम डेटा (एप्लिकेशन रन के बीच ) की क्षमता
  • डेटा स्टोर की क्वेरी करने की क्षमता (जैसे कि अगर मैंने A, B, C देखा है, तो मैं अपने प्रशिक्षित 4-, 3-, 2-, 1-ग्राम डेटा सेट का उपयोग करने के लिए सबसे अधिक बार देखी जाने वाली वस्तु जानना चाहूंगा। )

    आवेदन सबसे अधिक संभावना है, भारी पढ़ा जाएगा, डेटा सेट सबसे अधिक संभावना है कि अक्सर मुकर नहीं किया जाएगा

  • समाधान .NET फ्रेमवर्क को नियोजित करता है (4.0 तक)

अब ऐसे कार्य के लिए कौन सा डिज़ाइन बेहतर होगा?

  • एक निश्चित तालिका प्रत्येक के लिए एक एसक्यूएल सर्वर (MSSQL, MySQL, ...) द्वारा प्रबंधित n (जैसे। द्वि-ग्राम के लिए समर्पित टेबल, त्रिकोणीय ग्राम, आदि)
  • या एक NoSQL डॉक्यूमेंट डेटाबेस सॉल्यूशन जो पहले n -1 को डॉक्यूमेंट की कुंजी के रूप में स्टोर करता है , और डॉक्यूमेंट में n -th वैल्यू और अवलोकित आवृत्तियों को शामिल किया जाता है?
  • या कुछ अलग है?

3
मुझे लगता है कि यह स्टैक ओवरफ्लो पर बेहतर अनुकूल होगा।
कोनराड रुडोल्फ

1
शायद एक trie (उपसर्ग वृक्ष) डेटा संरचना आपकी आवश्यकताओं के अनुरूप होगी?
शेड्यूलर

1
मैं सुझाव देता हूं कि स्टैक ओवरफ्लो या यहां तक ​​कि cstheory.stackexchange.com
स्टीव

ठीक है शुक्रिया। मैं वहाँ पर सवाल उठाने की कोशिश करूँगा।
मैनी

4
यह सवाल programmers.stackexchange.com के लिए पूरी तरह से अनुकूल है और इसे stackoverflow, IMO में माइग्रेट नहीं किया जाना चाहिए। यह बिल्कुल "व्हाइटबोर्ड स्थिति" सवाल है कि यहाँ पूछा जाना चाहिए की तरह है। विवरण के लिए मेटा की जाँच करें।
user281377

जवाबों:


8

यह देखते हुए कि आप N की इष्टतम सीमा नहीं जानेंगे, आप निश्चित रूप से इसे बदलना चाहते हैं। उदाहरण के लिए, यदि आपका आवेदन इस संभावना की भविष्यवाणी करता है कि एक निश्चित पाठ अंग्रेजी है, तो आप संभवतः एन 3..5 के लिए चरित्र एन-ग्राम का उपयोग करना चाहेंगे। (यही हमने प्रयोगात्मक रूप से पाया।)

आपने अपने आवेदन के बारे में विवरण साझा नहीं किया है, लेकिन समस्या पर्याप्त है। आप एक रिलेशनल डेटाबेस (या NoSQL दस्तावेज़-आधारित समाधान) में एन-ग्राम डेटा का प्रतिनिधित्व करना चाहते हैं। अपने स्वयं के समाधान का सुझाव देने से पहले, आप निम्नलिखित दृष्टिकोणों पर एक नज़र रखना चाहते हैं:

  1. Google ngrams को डेटाबेस में कैसे स्टोर करें?
  2. डेटाबेस में <n- तालिकाओं में एन-ग्राम का भंडारण
  3. रिलेशनल डेटाबेस के साथ Google वेब 1T 5-ग्राम का प्रबंधन करना

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

  create table ngram_1 (
      word1 nvarchar(50),
      frequency FLOAT,
   primary key (word1));

  create table ngram_2 (
      word1 nvarchar(50),
      word2 nvarchar(50),
      frequency FLOAT,
   primary key (word1, word2));

  create table ngram_3 (
      word1 nvarchar(50),
      word2 nvarchar(50),
      word3 nvarchar(50),
      frequency FLOAT,
   primary key (word1, word2, word3));

  create table ngram_4 (
      word1 nvarchar(50),
      word2 nvarchar(50),
      word3 nvarchar(50),
      word4 nvarchar(50),
      frequency FLOAT,
   primary key (word1, word2, word3, word4));

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

  INSERT [ngram_2] ([word1], [word2], [frequency]) VALUES (N'building', N'with', 0.5)
  INSERT [ngram_2] ([word1], [word2], [frequency]) VALUES (N'hit', N'the', 0.1)
  INSERT [ngram_2] ([word1], [word2], [frequency]) VALUES (N'man', N'hit', 0.2)
  INSERT [ngram_2] ([word1], [word2], [frequency]) VALUES (N'the', N'bat', 0.7)
  INSERT [ngram_2] ([word1], [word2], [frequency]) VALUES (N'the', N'building', 0.3)
  INSERT [ngram_2] ([word1], [word2], [frequency]) VALUES (N'the', N'man', 0.4)
  INSERT [ngram_2] ([word1], [word2], [frequency]) VALUES (N'with', N'the', 0.6)
  INSERT [ngram_3] ([word1], [word2], [word3], [frequency]) VALUES (N'building', N'with', N'the', 0.5)
  INSERT [ngram_3] ([word1], [word2], [word3], [frequency]) VALUES (N'hit', N'the', N'building', 0.3)
  INSERT [ngram_3] ([word1], [word2], [word3], [frequency]) VALUES (N'man', N'hit', N'the', 0.2)
  INSERT [ngram_3] ([word1], [word2], [word3], [frequency]) VALUES (N'the', N'building', N'with', 0.4)
  INSERT [ngram_3] ([word1], [word2], [word3], [frequency]) VALUES (N'the', N'man', N'hit', 0.1)
  INSERT [ngram_3] ([word1], [word2], [word3], [frequency]) VALUES (N'with', N'the', N'bat', 0.6)
  INSERT [ngram_4] ([word1], [word2], [word3], [word4], [frequency]) VALUES (N'building', N'with', N'the', N'bat', 0.5)
  INSERT [ngram_4] ([word1], [word2], [word3], [word4], [frequency]) VALUES (N'hit', N'the', N'building', N'with', 0.3)
  INSERT [ngram_4] ([word1], [word2], [word3], [word4], [frequency]) VALUES (N'man', N'hit', N'the', N'building', 0.2)
  INSERT [ngram_4] ([word1], [word2], [word3], [word4], [frequency]) VALUES (N'the', N'building', N'with', N'the', 0.4)
  INSERT [ngram_4] ([word1], [word2], [word3], [word4], [frequency]) VALUES (N'the', N'man', N'hit', N'the', 0.1)

सबसे संभावित अगले शब्द को क्वेरी करने के लिए, आप इस तरह से एक क्वेरी का उपयोग करेंगे।

  DECLARE @word1 NVARCHAR(50) = 'the'
  DECLARE @word2 NVARCHAR(50) = 'man'
  DECLARE @word3 NVARCHAR(50) = 'hit'
  DECLARE @bigramWeight FLOAT = 0.2;
  DECLARE @trigramWeight FLOAT = 0.3
  DECLARE @fourgramWeight FLOAT = 0.5

  SELECT next_word, SUM(frequency) AS frequency
  FROM (
    SELECT word2 AS next_word, frequency * @bigramWeight AS frequency
    FROM ngram_2
    WHERE word1 = @word3
    UNION
    SELECT word3 AS next_word, frequency * @trigramWeight AS frequency
    FROM ngram_3
    WHERE word1 = @word2
      AND word2 = @word3
    UNION
    SELECT word4 AS next_word, frequency * @fourgramWeight AS frequency
    FROM ngram_4
    WHERE word1 = @word1
      AND word2 = @word2
      AND word3 = @word3
    ) next_words
  GROUP BY next_word
  ORDER BY SUM(frequency) DESC

यदि आप अधिक ngram टेबल जोड़ते हैं, तो आपको उपरोक्त क्वेरी में एक और UNION क्लॉज जोड़ना होगा। आप देख सकते हैं कि पहली क्वेरी में मैंने word1 = @ word3 का उपयोग किया था। और दूसरी क्वेरी में, word1 = @ word2 और word2 = @ word3। ऐसा इसलिए है क्योंकि हमें एनग्राम डेटा के लिए क्वेरी में तीन शब्दों को संरेखित करने की आवश्यकता है । यदि हम तीन शब्दों के अनुक्रम के लिए सबसे अधिक संभावना वाला अगला शब्द चाहते हैं, तो हमें अनुक्रम में शब्दों के अंतिम शब्द के खिलाफ बिग्राम डेटा में पहले शब्द की जांच करने की आवश्यकता होगी ।

आप अपनी इच्छानुसार वजन मापदंडों को ट्विक कर सकते हैं। इस उदाहरण में, मैंने मान लिया कि उच्चतर "n" ग्राम अधिक विश्वसनीय होगा।

पुनश्च मैं विन्यास के माध्यम से किसी भी संख्या में ngram_N तालिकाओं को संभालने के लिए प्रोग्राम कोड की संरचना करेगा। आप ngram_5 और ngram -6 टेबल बनाने के बाद एन-ग्राम रेंज एन (1..6) का उपयोग करने के लिए कार्यक्रम को घोषित रूप से बदल सकते हैं।


इस क्वेरी के साथ, मुझे केवल वही आवृत्ति स्कोर दिखाई देता है जो आपके पास है। मैं अगले पूर्वानुमान शब्द का चयन कैसे करूँ? वाक्य की सबसे अधिक प्रासंगिकता कौन सी है?
टॉमसॉयर

अच्छी बात @TomSawyer। मैंने उत्तर में नमूना डेटा जोड़ा और एक नमूना प्रश्न दिया जो अगले संभावित शब्द को वापस करता है।
मैथ्यू रोडैटस

आपके अपडेट के लिए Tks। लेकिन हम यहां आवृत्ति की गणना कैसे कर सकते हैं? यानी: में ngram_2, मुहावरा building withहै फ्रीक 0.5 है। उसी के साथ एक ही सवाल @bigramWeight, कि क्या है? हालांकि मैं freq है क्षेत्र हम डेटाबेस अद्यतन हर बार अद्यतन किया जाएगा। यानी यदि उपयोगकर्ता अधिक स्ट्रिंग दर्ज करता है, तो इस स्ट्रिंग की आवृत्ति पुनर्गणना होगी? प्रत्येक वाक्यांश के कुल प्रयुक्त समय या उपस्थिति दर में 0.5 प्रतिशत 0.5 है?
टॉमस्वायर

BigramWeight और trigramWeight (आदि) समग्र गणना में अलग-अलग एन-ग्राम का वजन कैसे करें। यह कहने का एक सरल तरीका है कि लंबे समय तक एन-ग्राम में उच्च एन्ट्रापी होती है और आप चाहते हैं कि वे छोटे एन-ग्राम से अधिक "गिनती" कर सकें।
मैथ्यू रोडैटस 14

डेटाबेस को अपडेट करने के संदर्भ में, जाहिर है कि मैंने सभी विवरणों को कवर नहीं किया है और सुधार के लिए बहुत जगह है। उदाहरण के लिए, ngram तालिकाओं में nvarchars संग्रहीत करने के बजाय, आप शायद एक शब्द तालिका (word_id INT, शब्द NVARCHAR) में tokenize करना चाहते हैं और फिर ngram तालिकाओं में word_ids देखें। फिर से जाँच करने पर तालिकाओं को अद्यतन करने के लिए, यह सही है - आप केवल आवृत्ति क्षेत्र को अपडेट करेंगे।
मैथ्यू रोडेटस

3

दूसरों के सुझाव के विपरीत, मैं किसी भी डेटा संरचना को हैशमैप या की-वैल्यू स्टोर की तुलना में अधिक जटिल होने से बचाने के लिए सुझाव दूंगा।

अपनी डेटा एक्सेस आवश्यकताओं को ध्यान में रखें: a) 99% अनुरोध - क्वेरी ngram "आआ-bbb-ccc" और मूल्य को पुनः प्राप्त करें (या 0) b) 1% अनुरोध - विशिष्ट ngram c की गिनती सम्मिलित / अद्यतन करना) नहीं है (सी)।

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

यदि आपका ngram डेटा छोटा है (कहते हैं, <1 gb) और मेमोरी में फिट बैठता है, तो मैं ओवरहेड से बचने के लिए एक कुशल इन-प्रोग्राम मेमोरी स्ट्रक्चर (हैशमैप्स, ट्रीज़, ट्राइब्स इत्यादि) का उपयोग करने का सुझाव दूंगा; और फ्लैट फ़ाइलों के लिए बस क्रमबद्ध / deserialize। यदि आपका ngram डेटा टेराबाइट्स या अधिक है, तो आप कई नोड्स पर विभाजित NoSQL कुंजी-मूल्य स्टोर चुन सकते हैं।

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


1

सबसे कुशल नहीं है, लेकिन आप चाहते हैं जैसे डेटाबेस के लिए सरल और wedded:

Table: word
Colums:
word (int, primary key) - a unique identifier for each word
text (varchar) - the actual word

Table: wordpos
Columns:
document (int) - a unique identified for the document of this word
word (int, foreign key to word.word) - the word in this position
pos (int) - the position of this word (e.g., first word is 1, next is 2, ...)

wordpos में डॉक्यूमेंट और पॉज़ पर इंडेक्स होना चाहिए।

bigrams हैं:

select word1.text as word1, word2.text as word2
from wordpos as pos1, wordpos as pos2, word as word1, word as word2
where pos1.document = pos2.document
      and pos1.pos = pos2.pos - 1
      and word1.word = pos1.word
      and word2.word = pos2.word

फिर आप आवृत्तियों और सामान के लिए अपने तरीके को गिन () और समूह कर सकते हैं।

ट्रिगर्स में बदलने के लिए, इस स्ट्रिंग को वर्ड 3 शामिल करने के लिए आसानी से जेनरेट किया जाता है।

मैंने वास्तव में पहले भी ऐसा किया है (भले ही एसक्यूएल वहाँ शायद थोड़ा जंग खाए हुए है)। मैं फ्लैट फ़ाइलों के एक सेट पर बस गया जिसे आसानी से खोजा जा सकता था और फिर डिस्क को बंद कर दिया गया। Kinda आपके हार्डवेयर पर निर्भर करता है कि इसे बेहतर कैसे करें।


1

अपने एप्लिकेशन की खोजों को बिग्रेड और ट्रिगर से बेहतर बनाने की कोशिश करते हुए, अनिवार्य रूप से, मैंने आपका प्रश्न देखा।

यदि आवश्यकताओं में से एक वितरित फ़ाइल सिस्टम या डेटाबेस को क्वेरी करने की क्षमता है, तो यह आपके लिए भी दिलचस्प हो सकता है: पेपर पिबिरी और वेंतुरिनी 2018 "बड़े पैमाने पर एन-ग्राम डेटासेट को संभालना कुशलतापूर्वक" एन-ग्राम डेटा को स्टोर करने के लिए एक कुशल तरीका रेखांकित करता है। रनटाइम और स्पेस की शर्तें। उन्होंने https://github.com/jermp/tongrams पर अपने कार्यान्वयन की पेशकश की है

प्रत्येक "n"-n-ग्राम को एक अलग तालिका में न्यूनतम सही हैश फ़ंक्शन द्वारा बहुत तेज चयन और क्वेरी क्षमताओं के साथ एक्सेस किया जाता है। तालिकाओं को स्थिर और मुख्य कोड द्वारा निर्मित किया जाता है, जो Google n- ग्राम पाठ फ़ाइलों के प्रारूप में इनपुट का उपयोग करता है।

मैंने अभी तक कोड का उपयोग नहीं किया है, लेकिन कई तरीके हैं जो आप अपनी खुली आवश्यकताओं के साथ कर सकते हैं जहां आपके प्रश्न हैं।

एक तरीका: अगर किसी सर्वलेट का .NET समतुल्य डेटाबेस या डेटास्टोर के साथ उपयोग किया जाता है, और यदि आपको स्टोरेज स्पेस को संरक्षित करने की आवश्यकता है, तो डेटाबेस में प्रत्येक एनग्राम टेबल को बाइनरी रूप में संग्रहीत करें / डेटास्टोर में टेबल एक विकल्प है (एक डेटाबेस / सभी 1-ग्राम के लिए कुशल ngram कोड की परिणामी स्थैतिक फ़ाइल के लिए / डेटास्टोर टेबल, 2-ग्राम के लिए एक और, आदि)। कुशल एन-ग्राम कोड (आपके सर्वलेट द्वारा सुलभ होने के लिए लिपटे) को लागू करके क्वेरीज़ का संचालन किया जाएगा। यह एक वितरित डेटाबेस बनाने के लिए एक काम के आसपास है जो वितरित फ़ाइल सिस्टम पर फ़ाइलों तक पहुंचने के लिए कुशल एन-ग्राम कोड का उपयोग कर रहा है। ध्यान दें कि बाइनरी डेटाबेस / डेटास्टोर तालिकाओं में प्रत्येक में अंतर्निहित फ़ाइल-सिस्टम का फ़ाइल-आकार प्रतिबंध है।

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