2013-06-27 4 views
7

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

मेरे पास टेक्स्ट का बड़ा डेटाबेस है, और मैं एक इंडेक्स रखता हूं जो मुझे बताता है, प्रत्येक शब्द के लिए, जिसमें फ़ाइल है (IDdoc), और फ़ाइल में यह कहां है (position)। (एक शब्द कई फाइलों में और एक फाइल में कई स्थानों पर हो सकता है।)

इस प्रकार मैं प्रत्येक शब्द के लिए एक वेक्टर रखें:

vector<pair<IDdoc,position>> occurences_of_word; 

(वेक्टर में IDdoc द्वारा और उसके बाद की स्थिति के अनुसार क्रमबद्ध किया जाता है, आरोही क्रम।)

मेरे पास शब्द से बना वस्तु है। यह वाक्यांश है I am looking for।

वाक्यांश में प्रत्येक शब्द मुझे पता है कि जो दस्तावेज इस वाक्यांश होते हैं, इसलिए IDdoc रों का एक वेक्टर लौटने चाहते हैं के लिए

typedef std::string  Word_t; 
typedef unsigned int WordPosition_t; 
typedef unsigned int IDdocument_t; 

vector<pair<IDdocument_t,WordPosition_t> > IndiceInvertidoBooleanoConPosicion::_interseccion_dos_listas 
    (const vector<pair<IDdocument_t,WordPosition_t>> & v1, 
    const vector<pair<IDdocument_t,WordPosition_t>> & v2) 
{ 
vector<pair<IDdocument_t,WordPosition_t> > intersection; 

IDdocument_t ID_doc_one, ID_doc_two; 

int i = 0; 
int j = 0; 
const int MAX_INDEX_V1 = v1.size() -1; 
const int MAX_INDEX_V2 = v2.size() -1; 

while(i <= MAX_INDEX_V1 && j <= MAX_INDEX_V2) 
{ 
    ID_doc_one = v1[i].first; 
    ID_doc_two = v2[j].first; 
    if (ID_doc_one < ID_doc_two) 
     i++; 
    else if (ID_doc_one > ID_doc_two) 
     j++; 
    else // The words were found in the same document! 
    { 
     WordPosition_t pos_word_one = v1[i].second; 
     WordPosition_t pos_word_two = v2[j].second; 

     // The words make a phrase! Return pos_two for the next intersection finding step 
     if (pos_word_one + 1 == pos_word_two) 
     { 
      intersection.push_back(make_pair(ID_doc_one,pos_word_two)); 
      i++; 
      j++; 
     } 

     // Phrase not found 
     else 
     { 
      if (pos_word_one < pos_word_two) 
       i++; 
      else 
       j++; 
     } 

    } 
} 

return intersection; 
} 

int find_phrase(const string phrase, vector<IDdocument_t> & id_docs) 
{ 
Word_t word; 
id_docs.clear(); 
Text parsed_phrase; 
// Extract the relevant words from the phrase 
parsed_phrase.parse(phrase); 

vector<pair<IDdocument_t,WordPosition_t> > intersection; 
vector<pair<IDdocument_t,WordPosition_t> > second_vector; 

while (parsed_phrase.get_next_word(word) != RES_END) 
{ 
    _find_vector_words(word,intersection); 

    while (parsed_phrase.get_next_word(word) != RES_END) 
    { 
     _find_vector_words(word,second_vector); 

     intersection = _intersect_two_words(intersection,second_vector); 

    } 
} 

for (unsigned int i = 0; i < intersection.size(); i ++) 
{ 
    IDdocument_t id_doc = intersection[i].first; 
    if(std::find(id_docs.begin(), id_docs.end(), id_doc) == id_docs.end()) 
     id_docs.push_back(id_doc); 
} 

return RES_OK; 
} 
+0

सुनिश्चित नहीं हैं कि क्या आप वास्तव में पूछ रहे हैं - आप जो आपके दस्तावेजों के होते हैं "एक संख्या की पहचान करने के लिए कैसे पूछ रहे हैं एक फिलिप्स स्क्रूड्राइवर ", या कौन से दस्तावेज़ों में शब्द" ए "," संख्या "" एक "," फिलिप्स "या" स्क्रूड्राइवर "होता है। यदि पूर्व में, क्या उन्हें लगातार होना चाहिए या "एक पेंचदार और पोजिड्रिव के लिए एक स्क्रूड्राइवर पर हैंडल की संख्या एक मैच होगी"? –

+0

@ मैट्स पीटरसन, उन्हें लगातार होने की आवश्यकता है। –

+0

संबंधित: http://stackoverflow.com/questions/2659120/how-to-search-phrase-queries-in-inverted-index- संरचना – jogojapan

उत्तर

2

स्ट्रिंग प्रस्तुति से एक विशेष शब्द देखने के लिए, शायद आप map जैसे कुछ देखना चाहते हैं। परिणामों का एक साधारण संघ बनाने के लिए शायद आप set चाहते हैं। यह कार्यान्वयन एक अत्यधिक वांछनीय अंतिम कार्यान्वयन (सी.एफ.मैला वाक्यांश वाक्यांश)।

#include <vector> 
#include <map> 
#include <set> 
#include <iostream> 
#include <string> 

typedef std::string IDdoc; 
typedef int position; 

typedef std::pair<IDdoc,position> Occurrence; 
typedef std::vector<Occurrence> OccurrencesOfWord; 
typedef std::map<std::string /*word*/, OccurrencesOfWord> Dictionary; 
typedef std::set<IDdoc> Matches; 

bool findMatchesForPhrase(const std::string& phrase, const Dictionary& dictionary, Matches& matches) 
{ 
    size_t pos = 0; 
    size_t len = 0; 
    while (pos < phrase.length()) { 
     size_t end = phrase.find(' ', pos); 
     size_t len = ((end == phrase.npos) ? phrase.length() : end) - pos; 
     std::string word(phrase, pos, len); 
     pos += len + 1; // to skip the space. 

     // ignore words not in the dictionary. 
     auto dictIt = dictionary.find(word); 
     if (dictIt == dictionary.end()) 
      continue; 

     auto& occurrences = dictIt->second; // shortcut/alias,. 
     for (auto& occurIt : occurrences) { 
      // Add all the IDdoc's of this occurence to the set. 
      matches.insert(occurIt.first); 
     } 
    } 

    return !matches.empty(); 
} 

void addToDictionary(Dictionary& dict, const char* word, const char* doc, int position) 
{ 
    dict[word].push_back(std::make_pair(std::string(doc), position)); 
} 

int main(int argc, const char** argv) 
{ 
    std::string phrase("pizza is life"); 
    Dictionary dict; 

    addToDictionary(dict, "pizza", "book1", 10); 
    addToDictionary(dict, "pizza", "book2", 30); 
    addToDictionary(dict, "life", "book1", 1); 
    addToDictionary(dict, "life", "book3", 1); 
    addToDictionary(dict, "goat", "book4", 99); 

    Matches matches; 
    bool result = findMatchesForPhrase(phrase, dict, matches); 

    std::cout << "result = " << result << std::endl; 
    for (auto& ent : matches) { 
     std::cout << ent << std::endl; 
    } 

    return 0; 
} 

पर इस की ऑनलाइन डेमो: http://ideone.com/Zlhfua


अपने परिवर्तनों को संबोधित करने के लिए ऊपर का पालन करें:

while(i < SIZE_VECTOR_ONE && j < SIZE_VECTOR_TWO) 
{ 
    if (ID_doc_one < ID_doc_two) 
    { 
     ID_doc_one = v1[++i].first; 

कहते हैं कि "SIZE_VECTOR 1" चलें 1. इसका मतलब है कि एक है कि वहाँ है वेक्टर में तत्व, तत्व [0]। यदि ID_doc_one 0 है और ID_doc_two 1 है, तो

if (0 < 1) { 
    ID_doc_one = v1[1].first; 

जो अमान्य है। आप iterators या संकेत का उपयोग कर से बेहतर हो सकता है:

while (oneIt != v1.end() && twoIt != v2.end()) { 
    if (oneIt->first < twoIt->first) { 
     ++oneIt; 
     continue; 
    } else if (*twoIt < *oneIt) { 
     ++twoIt; 
     continue; 
    } 
    // same documentId in both lists, snag positions. 
    ... 
} 

इसके बाद, इस थोड़े टूट दिखता है:

else { 
    } // To avoid "out of range" errors <-- but also ends the "else" 
     if (i < SIZE_VECTOR_ONE - 1) 
      ID_doc_one = v1[++i].first; 
     if (j < SIZE_VECTOR_TWO - 1) 
      ID_doc_two = v2[++j].first; 
    } 

और मुझे आश्चर्य है कि अगर आप एक ही दस्तावेज़ लेकिन कई पदों है क्या होता है?

यह अगले लीख picky है, लेकिन यह मुझे काफी समय लगा पार्स करने के लिए

WordPosition_t pos_one = v1[i].second; 
    WordPosition_t pos_two = v2[j].second; 

    // The words make a phrase! Return pos_two for the next intersection finding step 
    if (pos_one + 1 == pos_two) 

यह बेहद स्पष्ट लगता है यह लिखने के रूप में आप यह कह सकते हैं "(यदि दूसरा शब्द स्थिति के बाद में है पहला शब्द):

WordPosition_t posFirstWord = v1[i].second; 
    WordPosition_t posSecondWord = v2[j].second; 

    // The words make a phrase! Return pos_two for the next intersection finding step 
    if (posSecondWord == posFirstWord + 1) 

यह अगले भाग के बाद से दोनों धाराएं एक आम में वह हिस्सा फहराने की मैं और जे और अद्यतन ID_doc_one और दो बढ़ाने के लिए इरादा किया जाना है, यह भावना बना सकता था दिखाई दिया, एक तरह से भ्रामक था अगर ब्लॉक के बाद अनुभाग, लेकिन फिर else {} इसे बनाया यह कहना मुश्किल है कि आप वास्तव में क्या कर रहे थे।

if (pos_one + 1 == pos_two) 
    { 
     intersection.push_back(make_pair(ID_doc_one,pos_two)); 
     ID_doc_one = v1[++i].first; 
     ID_doc_two = v2[++j].first; 
    } 

    else { 
    } // To avoid "out of range" errors 
     if (i < SIZE_VECTOR_ONE - 1) 
      ID_doc_one = v1[++i].first; 
     if (j < SIZE_VECTOR_TWO - 1) 
      ID_doc_two = v2[++j].first; 
    } 

जब आप दोनों सरणियों से मेल खाते हैं, तो आप हमेशा बढ़ाने के लिए मैं और जे दोनों, यह हालत नहीं है, चाहता हूँ, मैं भी यकीन नहीं है तुम क्यों pos_two उपयोग कर रहे हैं के बाद से वाक्यांश वास्तव में pos_one पर मिला था?

यह मैं इसे कैसे लिखा होता है:

#include<iostream> 
#include<map> 
#include<vector> 
#include<string> 

typedef std::string   Word_t; 
typedef unsigned int  WordPosition_t; 
typedef unsigned int  IDdocument_t; 

typedef std::pair<IDdocument_t, WordPosition_t> DocumentPosition_t; 
typedef std::vector<DocumentPosition_t> WordReferences_t; 

WordReferences_t _intersect_two_words(const WordReferences_t& v1, const WordReferences_t& v2) 
{ 
    // all the locations where the words occur one after the other. 
    WordReferences_t intersection; 

    auto firstIt = v1.begin(); 
    auto secondIt = v2.begin(); 
    while (firstIt != v1.end() && secondIt != v2.end()) 
    { 
     if (firstIt->first < secondIt->first) 
     { 
      ++firstIt; 
      continue; 
     } 
     // find the second word in the same document and AFTER the first word. 
     if (secondIt->first < firstIt->first || secondIt->second < firstIt->second + 1) 
     { 
      ++secondIt; 
      continue; 
     } 
     // first word wasn't just before the second, it's not a phrase. 
     if (secondIt->second > firstIt->second + 1) 
     { 
      ++firstIt; 
      continue; 
     } 
     // We found a phrase. 
     intersection.emplace_back(*firstIt); 
     ++firstIt; 
     ++secondIt; 
    } 

    return intersection; 
} 

int main() 
{ 
    WordReferences_t v1, v2; 
    v1.push_back(std::make_pair(10, 5)); 
    v1.push_back(std::make_pair(10, 25)); 
    v1.push_back(std::make_pair(11, 10)); 
    v1.push_back(std::make_pair(12, 1)); 
    v1.push_back(std::make_pair(12, 11)); 
    v1.push_back(std::make_pair(12, 21)); 
    v1.push_back(std::make_pair(12, 31)); 
    v1.push_back(std::make_pair(15, 11)); 
    v1.push_back(std::make_pair(100, 1)); 
    v1.push_back(std::make_pair(100, 11)); 
    v1.push_back(std::make_pair(100, 21)); 
    v1.push_back(std::make_pair(101, 11)); 
    v1.push_back(std::make_pair(102, 11)); 
    v1.push_back(std::make_pair(102, 13)); 
    v1.push_back(std::make_pair(102, 14)); 
    v1.push_back(std::make_pair(103, 11)); 
    v1.push_back(std::make_pair(103, 13)); 

    v2.push_back(std::make_pair(10, 11)); 
    v2.push_back(std::make_pair(12, 10)); 
    v2.push_back(std::make_pair(12, 40)); 
    v2.push_back(std::make_pair(16, 11)); 
    v2.push_back(std::make_pair(100, 12)); // match 
    v2.push_back(std::make_pair(101, 12)); // match 
    v2.push_back(std::make_pair(101, 13)); 
    v2.push_back(std::make_pair(101, 14)); 
    v2.push_back(std::make_pair(102, 12)); //match 
    v2.push_back(std::make_pair(103, 1)); 
    v2.push_back(std::make_pair(103, 10)); 
    v2.push_back(std::make_pair(103, 12)); // match 
    v2.push_back(std::make_pair(103, 15)); 

    auto intersection = _intersect_two_words(v1, v2); 
    for (auto entry : intersection) 
    { 
     std::cout << entry.first << ", " << entry.second << "+" << (entry.second + 1) << std::endl; 
    } 

    return 0; 
} 

लाइव उदाहरण: http://ideone.com/XRfhAI

+0

अरे, क्या आप मेरी मूल पोस्ट की जांच कर रहे हैं? मैंने अपना समाधान पोस्ट कर दिया है। धन्यवाद! –

+1

मेरे संशोधित उत्तर देखें। – kfsone

+0

धन्यवाद @kfsone! मैंने कोड के अपने नए संस्करण के साथ अपनी पोस्ट अपडेट की। –

0

अगर यह सबसे कारगर है मैं नहीं जानता, लेकिन आप words[0] के दस्तावेज/पदों के साथ शुरू कर सकता है:

यहाँ एक समाधान पर मेरे प्रयास है। फिर words[1] पर जाएं और उसी दस्तावेज़ के लिए words[0].position + words[0].length + 1 के बराबर स्थितियों वाले दस्तावेज़ों को छेड़छाड़ करें। फिर words के बाकी हिस्सों में भी पुन: प्रयास करें। इसे लंबे वाक्यांशों के लिए बहुत तेज़ी से कम करना चाहिए?

0

आप दिया गया है के रूप में, डेटा संरचना का उपयोग कर रहे हैं वास्तव में एक पूर्ण उल्टे सूचकांक, के रूप में विकिपीडिया द्वारा कहा गया है:

वहाँ उल्टे अनुक्रमित के दो मुख्य वेरिएंट हैं: एक रिकॉर्ड स्तर उल्टे सूचकांक (या उल्टे फ़ाइल इंडेक्स या सिर्फ उलटा फ़ाइल) प्रत्येक शब्द के लिए दस्तावेज़ों के संदर्भों की एक सूची शामिल है। एक शब्द स्तर उलटा सूचकांक (या पूर्ण उलटा इंडेक्स या उलटा सूची) अतिरिक्त रूप से दस्तावेज़ के भीतर प्रत्येक शब्द की स्थिति शामिल है। [2] बाद वाला फॉर्म अधिक कार्यक्षमता प्रदान करता है (वाक्यांश खोजों की तरह), लेकिन इसे बनाए जाने के लिए अधिक समय और स्थान की आवश्यकता होती है।

कहा जा रहा है, तो आप भी एक मुहावरा सूचकांक बनाने की कोशिश कर सकते हैं:

http://ww2.cs.mu.oz.au/~jz/fulltext/acmtois04.pdf

(एक प्रदर्शन के रूप चित्र 2 देखें)।

यदि आप वाक्यांश सूचकांक नहीं बना रहे हैं, तो आप क्या कर सकते हैं (मुझे विश्वास है), केवल एक विशिष्ट शब्द वाले दस्तावेज़ों को पुनर्प्राप्त करना होगा, आपके द्वारा किए गए दस्तावेज़ों के सेट को अलग-अलग करें, जैसे आप शब्दों से क्वेरी बढ़ाते हैं वाक्यांशों के लिए और फिर आखिरकार दस्तावेज़ पर वापस जाएं और देखें कि क्या आपके पास लौटाए गए प्रत्येक दस्तावेज़ में वास्तव में "अलग-अलग स्थितियों पर एक दूसरे को अलग करने वाले शब्दों" के बजाय "वाक्यांश" है।

+0

हां, यह वास्तव में एक उलटा इंडेक्स के कार्यान्वयन का हिस्सा है :-) –

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