2016-09-01 10 views
11

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

पहले चरण में, जहां मैं कतार पंजीकृत करता हूं, उस मशीन पर, मैं HTML फ़ाइलों का एक सबसेट चुनता हूं और उनसे लापरवाही से read_html फ़ंक्शन (rvest पैकेज से, मैंने XML से समान फ़ंक्शन का भी प्रयास किया है पैकेज लेकिन मुझे स्मृति रिसाव की समस्याएं मिल रही थीं) कई एचटीएमएल पृष्ठों की सामग्री को संग्रहित करने वाली एक अनूठी सूची प्राप्त करने के लिए।

फिर मैं इस सूची में एक इटरेटर का उपयोग करता हूं ताकि इसे फोरच को खिलाने के लिए छोटे हिस्से प्राप्त हो सकें।

पूर्वानुमान के अंदर मैं डेटा.फ्रेम (HTML) टेम्पलेट का उपयोग कर रहा हूं (HTML_table फ़ंक्शन और कुछ मूल डेटा मैनिपुलेशन का उपयोग कर रहा हूं) और मैं एक सूची लौटाता हूं जिसका तत्व साफ डेटा हैं। फ्रेम।

मैंने जीत 8 पर डूस्नो बैकएंड और यूबंटू 16.04 पर डूरेडिस दोनों का उपयोग करने का प्रयास किया है।

पहले मामले में रिक्त सूचियों की एक सूची लौटा दी जाती है जबकि दूसरी तरफ मेमोरी मैपिंग की त्रुटि फेंक दी जाती है; आप प्रश्न के बहुत नीचे ट्रेसबैक पा सकते हैं।

मेरी समझ के लिए जो मैं कोर को भेज रहा हूं, वह मुझे समझने के लिए व्यवहार नहीं कर रहा है। मैंने चारों ओर इकट्ठा किया है कि सूची वस्तु केवल पॉइंटर्स का एक सेट हो सकती है लेकिन मैं इसकी पुष्टि करने में सक्षम नहीं हूं; शायद यह मुद्दा हो सकता है? क्या एकाधिक HTML पृष्ठों के डेटा को "encapsulate" करने के लिए "सूची तरीका" का कोई विकल्प है?

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

library(rvest) 
library(foreach) 

#wikipedia pages of olympic medalist between 1992 and 2016 are 
# downloaded for reproducibility 
for(i in seq(1992, 2016, by=4)){ 

    html = paste("https://en.wikipedia.org/wiki/List_of_", i, "_Summer_Olympics_medal_winners", sep="") 
    con = url(html) 
    htmlCode = readLines(con) 
    writeLines(htmlCode, con=paste(i, "medalists", sep="_")) 
    close(con) 

} 

#declaring the redis backend (doSNOW code is also included below) 

#note that I am using the package from 
#devtools::install_github("bwlewis/doRedis") due to a "nodelay error" 
#(more info on that here: https://github.com/bwlewis/doRedis/issues/24) 
# if it is not your case please drop the nodelay and timeout options 

#Registering cores ---Ubuntu--- 
cores=2 
library('doRedis') 
options('redis:num'=TRUE) 
registerDoRedis("jobs", nodelay=FALSE) 
startLocalWorkers(n=cores, "jobs", timeout=2, nodelay=FALSE) 
foreachOpt <- list(preschedule=FALSE) 


#Registering cores ---Win--- 
#cores=2 
#library("doSNOW") 
#registerDoSNOW(makeCluster(cores, type = "SOCK")) 


#defining the iterator 
iterator <- function(x, ...) { 
    i <- 1 
    it <- idiv(length(x), ...) 

    if(exists("chunks")){ 
    nextEl <- function() { 
     n <- nextElem(it) 
     ix <- seq(i, length=n) 
     i <<- i + n 
     x[ix] 
    } 
    }else{ 
    nextEl <- function() { 
     n <- nextElem(it) 
     ix <- seq(i, i+n-1) 
     i <<- i + n 
     x[ix] 
    } 
    } 
    obj <- list(nextElem=nextEl) 
    class(obj) <- c(
    'ivector', 'abstractiter','iter') 
    obj 
} 

#reading files 
names_files<-list.files() 
html_list<-lapply(names_files, read_html) 

#creating iterator 
ChunkSize_html_list<-2 
iter<-iterator(html_list, chunkSize=ChunkSize_html_list) 

#defining expanding list (thanks StackOverflow and many thanks to 
#JanKanis's answer : http://stackoverflow.com/questions/2436688/append-an-object-to-a-list-in-r-in-amortized-constant-time-o1 ) 
expanding_list <- function(capacity = 10) { 
    buffer <- vector('list', capacity) 
    length <- 0 

    methods <- list() 

    methods$double.size <- function() { 
    buffer <<- c(buffer, vector('list', capacity)) 
    capacity <<- capacity * 2 
    } 

    methods$add <- function(val) { 
    if(length == capacity) { 
     methods$double.size() 
    } 

    length <<- length + 1 
    buffer[[length]] <<- val 
    } 

    methods$as.list <- function() { 
    b <- buffer[0:length] 
    return(b) 
    } 

    methods 
} 

#parallelized part 
clean_data<-foreach(ite=iter, .packages=c("itertools", "rvest"), .combine=c, 
.options.multicore=foreachOpt, .options.redis=list(chunkSize=1)) %dopar% { 

    temp_tot <- expanding_list() 
     for(g in 1:length(ite)){ 

     #extraction of data from tables 
     tables <- html_table(ite[[g]], fill=T, header = T) 

     for(i in 1:length(tables)){ 

      #just some basic data manipulation 
      temp<-lapply(tables, function(d){d[nrow(d),]}) 
      temp_tot$add(temp) 
      rm(temp) 
      gc(verbose = F) 
     } 
     } 
    #returning the list of cleaned data.frames to the foreach 
    temp_tot$as.list() 
} 

त्रुटि फेंक दिया जब redis बैकएंड का उपयोग कर:

*** caught segfault *** 
address 0x60, cause 'memory not mapped' 


Traceback: 
1: .Call("xml2_doc_namespaces", PACKAGE = "xml2", doc) 
2: doc_namespaces(doc) 
3: xml_ns.xml_document(x) 
4: xml_ns(x) 
5: xpath_search(x$node, x$doc, xpath = xpath, nsMap = ns, num_results = Inf) 
6: xml_find_all.xml_node(x, ".//table") 
7: xml2::xml_find_all(x, ".//table") 
8: html_table.xml_document(ite[[g]], fill = T, header = T) 
9: html_table(ite[[g]], fill = T, header = T) 
10: eval(expr, envir, enclos) 
11: eval(.doRedisGlobals$expr, envir = .doRedisGlobals$exportenv) 
12: doTryCatch(return(expr), name, parentenv, handler) 
13: tryCatchOne(expr, names, parentenv, handlers[[1L]]) 
14: tryCatchList(expr, classes, parentenv, handlers) 
15: tryCatch({ lapply(names(args), function(n) assign(n, args[[n]], pos = .doRedisGlobals$exportenv)) if (exists(".Random.seed", envir = .doRedisGlobals$exportenv)) {  assign(".Random.seed", .doRedisGlobals$exportenv$.Random.seed,    envir = globalenv()) } tryCatch({  if (exists("set.seed.worker", envir = .doRedisGlobals$exportenv))    do.call("set.seed.worker", list(0), envir = .doRedisGlobals$exportenv) }, error = function(e) cat(as.character(e), "\n")) eval(.doRedisGlobals$expr, envir = .doRedisGlobals$exportenv)}, error = function(e) e) 
16: FUN(X[[i]], ...) 
17: lapply(work[[1]]$argsList, .evalWrapper) 
18: redisWorker(queue = "jobs", host = "localhost", port = 6379,  iter = Inf, linger = 30, log = stdout(), timeout = 2, nodelay = FALSE) 
aborting ... 
+6

बधाई और stackoverflow पर स्वागत करते हैं। – Tensibai

+0

मुझे लगता है कि आप यहां बहुत चालाक होने की कोशिश कर रहे हैं। मुझे बंद करने का उपयोग करने का कोई कारण नहीं दिख रहा है। आप इस "विस्तार सूची" आवश्यकता क्यों है? जाहिर है, आप जानते हैं कि कैसे बड़े सूचियों होने की जरूरत है, इसलिए उन्हें 'का उपयोग कर वेक्टर (मोड =" सूची ", लंबाई = लंबाई (टेबल्स))' पूर्व आवंटित। – Roland

+0

हाय रोलाण्ड, मैं अपने सुझाव के लिए दो आपत्तियों की है।सबसे पहले, समस्या को स्पष्ट करने के लिए, यह है कि "temp_tot" सभी पृष्ठों (जी-लूप) से सभी तालिकाओं (आई-लूप) की सभी (अंतिम पंक्तियां) एकत्र करता है और प्रत्येक पृष्ठ के लिए तालिकाओं का # ज्ञात नहीं है। मैं देखता हूं कि इसे i-loop (आपके कोड का उपयोग करके) में बनाई गई सूचियों (सी-) (जी-लूप के अंत में) द्वारा हल किया जा सकता है। दूसरी आपत्ति, जिसने मुझे विस्तारित करना पसंद किया .list(), "सी() रास्ता" से उत्पन्न घोंसला वाली संरचना के कारण है (जी-इंडेक्स से विरासत में पहली अनुक्रमणिका, आई-इंडेक्स से दूसरी इकाई) जो कि expanding.list() – dgdi

उत्तर

3

मुझे लगता है कि समस्या यह है कि आप "read_html" को फोन करके गुरु पर XML/HTML दस्तावेज़ वस्तुओं बना रहे हैं, और उसके बाद के प्रसंस्करण है उन्हें श्रमिकों पर। मैंने कुछ प्रयोगों की कोशिश की है, और ऐसा लगता है कि यह काम नहीं करता है, शायद इसलिए कि उन वस्तुओं को क्रमबद्ध नहीं किया जा सकता है, श्रमिकों को भेजा जा सकता है, और फिर सही ढंग से deserialized। मुझे लगता है कि ऑब्जेक्ट्स भ्रष्ट हैं, जिससे श्रमिकों को "html_table" फ़ंक्शन का उपयोग करके उन पर काम करने का प्रयास करने का कारण बनता है।

मेरा सुझाव है कि आप फ़ाइल नाम से अधिक पुनरावृति करने के लिए इतना है कि श्रमिकों "read_html" खुद को कॉल कर सकते हैं, इस प्रकार XML दस्तावेज़ वस्तुओं serializing से बचने के लिए अपने कोड को संशोधित।

library(xml2) 
library(snow) 
cl <- makeSOCKcluster(3) 
clusterEvalQ(cl, library(xml2)) 

# Create XML documents on the master 
docs <- lapply(1:10, 
     function(i) read_xml(paste0("<foo>", i, "</foo>"))) 

# Call xml_path on XML documents created on master 
r1 <- lapply(docs, xml_path)   # correct results 
r2 <- clusterApply(cl, docs, xml_path) # incorrect results 

# This seems to work... 
docs2 <- clusterApply(cl, 1:10, 
     function(i) read_xml(paste0("<foo>", i, "</foo>"))) 

# But this causes a segfault on the master 
print(docs2) 

मैं बर्फ कार्यों के लिए इस्तेमाल किया सत्यापित करने के लिए सीधे है कि समस्या foreach या doSNOW में नहीं था:


यहाँ परीक्षण कोड है कि मैं के साथ प्रयोग के कुछ है। अपने पहले प्रश्न के लिए

+0

से बचाता है हाय स्टीव, आपके समय के लिए बहुत धन्यवाद, आपका जवाब वास्तव में एक प्रमुख प्रगति है और अब मैं साफ करना शुरू कर सकता हूं। 'क्लस्टरएपली (सीएल, 1:10, फ़ंक्शन (i) html_table (read_xml (paste0 (" ", i," ")), भरें = टी))' (क्लस्टर में निर्यात किए गए निवेश के साथ) सूची की एक सुलभ सूची का उपयोग करना data.frames का लौटा दिया गया है (महान!)। मुझे भी आपके doc2 के साथ त्रुटि मिली, शायद प्रिंट xml के साथ एक मुद्दा? हालांकि, इस सवाल में मैं अन्य मशीनों को नौकरी में शामिल होने की अनुमति देने के लिए मास्टर पर पढ़ने के द्वारा पृष्ठों की सामग्री को "incapsulating" था (जबकि "doRedis" मामले में), अगर मैं गलत हूं, तो कृपया मुझे सही करें, यह आपकी रणनीति के साथ संभव नहीं है – dgdi

+0

@ डीजीडीआई मैंने सोचा कि मास्टर से read_html फ़ंक्शन को ले जाने के लिए मजदूरों को मूल रूप से काम नहीं किया गया था, लेकिन शायद मुझे कुछ याद आ रहा है। –

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