none
effizient in dateien suchen RRS feed

  • Frage

  • Hallo, ich habe das Problem das ich ca 50 GB an ASCII Dateien nach verschiedenen Zeichenketten durchsuchen muss.

    Es sind ca 3000 Dateien mit Groessen zwischen 1MB und 50 MB.

    Es sind einfach zu viele Suchbegriffe um die alle mit der VS IDE internen "Suche in Dateien" zu suchen, deshalb wollte ich ein Programm dafür schreiben in VC++ mit MFC. Wie geht  man da am Besten vor? Einen möglichst großen zusammenhängenden Speicherbereich allokieren und die Dateien darin einlesen? Mit MemoryFiles arbeiten? Alle Dateien in eine Datenbank einlesen und mit Textindizierung arbeiten?

    Wäre für jeden Tipp dankbar.

    Freudi


    Freudi

    Dienstag, 7. Oktober 2014 07:50

Antworten

  • Hallo Freudi,

    Vorab ein paar Fragen:

    Verstehe ich das richtig daß Du zum einen 5-6 stellige Zahlen und zum anderen 32-Byte lange Sequenzen suchst?

    Etwas verwirrend: Wie kannst Du 20 Millionen Positionen als Ganzzahl haben wenn diese Zahlen nur 5-6 Stellen haben?

    Sind die Zahlen im als Text im XML abgelegt (so in der Form <value>12345</value>) oder muß auch die Zahl 123 im Text 012345 gefunden werden?

    Aus welchen Zeichen bestehen die IDs und sind diese auch zB durch Tags oder zumindest Trennzeichen begrenzt?

    Ich habe versuchsweise eine ~50 MB XML Datei erzeugt und eine Funktion geschrieben welche alle Ganzzahlen der Datei als std::set liefert. Wenn ich Datei 10x auswerte (486 MB) bekomme ich als Ergebnis 6321 Werte im Set und benötige auf einem i7 knapp 2,5 Sekunden. Bei mehr unterschiedlichen Werten wird das System langsamer da die Einfügeoperationen ins std::set aufwendiger werden.

    std::set<int> searchPositions(const std::vector<std::string>& filenames, size_t *bytesAnalyzed)
    {
    	std::set<int> result;
    
    	int count = 0;
    
    	std::vector<char> buffer;
    
    	for(const auto& filename : filenames)
    	{
    		std::cout << (++count) << "/" << filenames.size() << "  \r" << std::flush;
    
    		std::ifstream stream(filename, std::ios_base::binary);
    		if(stream.is_open())
    		{
    			stream.seekg(0, std::ios_base::end);
    			const auto size = static_cast<size_t>(stream.tellg());
    			stream.seekg(0, std::ios_base::beg);
    
    			if(buffer.size() < size + 1)
    				buffer.resize(size + 1);
    
    			stream.read(buffer.data(), size);
    			buffer[size] = 0;
    		
    			const char *ptr = buffer.data();
    
    			while(*ptr != 0)
    			{
    				if(*ptr >= '0' && *ptr <= '9')
    				{
    					int value = *ptr - '0';
    					++ptr;
    					for(; *ptr >= '0' && *ptr <= '9'; ++ptr)
    						value = value * 10 + (*ptr - '0');
    
    					result.insert(value);
    				} else
    				{
    					++ptr;
    				}
    			}
    
    			if(bytesAnalyzed)
    				*bytesAnalyzed += size;
    		}
    	}
    
    	std::cout << std::endl;
    
    	return result;
    }

    Die gesuchten Ganzzahlen können dann im Ergebnisset gesucht werden was relativ schnell geht. Noch schneller wäre es vermutlich auch die gesuchten Zahlen in ein Set zu packen und mittels std::set_difference eine Liste der fehlenden Werte zu erhalten.

    Wenn Du mir obenstehende Fragen beantworten kannst (und ich nochmal Zeit finde) dann sehe ich mir das Thema gerne noch mal an.

    mfg

    Andreas

    Mittwoch, 8. Oktober 2014 09:00

Alle Antworten

  • Hi Freudi,

    also welcher Algorhitmus am effiziensten ist hängt ganz von der Datenstruktur ab.

    Hier ein Link sortieralgorhitmus wo die verschiedenen Algorhitmen. Vom Prinzip kannst natürlich ein Bitmap von mehreren Dateien in den Speicher laden und dann durchsuchen oder da wir im Multiprozessor Zeitalter leben kannst du mehrere Dateien parallel durchsuchen lassen.

    Um dir aber bessere Tipps zu geben müsste ich mehr vom Problem wissen, herrscht schon in den Daten eine gewisse Struktur?
    Dienstag, 7. Oktober 2014 13:53
  • Es geht im Prinzip darum nachzuweisen das in XML Dateien Daten fehlen. Die Struktur der XML Daten soll dabei nicht berücksichtig werden. Es geht um Positionen im UTM Format also 5-6 stellige ganzzahlige Ziffern.

    Ich habe 20 Millionen Positionen als Ganzzahl und will jede davon in den Dateien suchen.

    Mir reicht wenn ich weiß wie viele gefunden werden und wie viele nicht. Außer der Kontrolle der Koordinaten gibt es noch ID's die sind immer 32 Byte lang und das sind 700.000 die zu suchen sind. Ich habe mal ganz simpel angefangen und lade jede Datei komplett in den Speicher und suche dann nacheinander die 700.000 Id's da drin.

    Das dauert aber viel zu lange, er hat jetzt nach 5 Stunden 20 Dateien durchsucht :-(

    Jetzt erweitere ich das mal auf mehrere Threads ....


    Freudi

    Dienstag, 7. Oktober 2014 14:09
  • Also kurz wird das suchen nicht...

    Parallelisieren wird schonmal einiges bringen. Nun kenne ich natürlich die Daten nicht vielleicht kannst du ja auf das Validieren verzichten und zählst einfach nur das vorkommen der Tags ....

    Wenn du mit UTM das UTM Koordinatensystem meinst dann kann ich mich noch dunkel dran erinnern das es auch sein kann das verschiedene Koordinaten die gleiche örtlichkeit darstellen, dann kommst du um ein Interpretieren nicht herum....


    • Bearbeitet Brian Dahl Dienstag, 7. Oktober 2014 17:05
    Dienstag, 7. Oktober 2014 17:05
  • Hallo Freudi,

    Vorab ein paar Fragen:

    Verstehe ich das richtig daß Du zum einen 5-6 stellige Zahlen und zum anderen 32-Byte lange Sequenzen suchst?

    Etwas verwirrend: Wie kannst Du 20 Millionen Positionen als Ganzzahl haben wenn diese Zahlen nur 5-6 Stellen haben?

    Sind die Zahlen im als Text im XML abgelegt (so in der Form <value>12345</value>) oder muß auch die Zahl 123 im Text 012345 gefunden werden?

    Aus welchen Zeichen bestehen die IDs und sind diese auch zB durch Tags oder zumindest Trennzeichen begrenzt?

    Ich habe versuchsweise eine ~50 MB XML Datei erzeugt und eine Funktion geschrieben welche alle Ganzzahlen der Datei als std::set liefert. Wenn ich Datei 10x auswerte (486 MB) bekomme ich als Ergebnis 6321 Werte im Set und benötige auf einem i7 knapp 2,5 Sekunden. Bei mehr unterschiedlichen Werten wird das System langsamer da die Einfügeoperationen ins std::set aufwendiger werden.

    std::set<int> searchPositions(const std::vector<std::string>& filenames, size_t *bytesAnalyzed)
    {
    	std::set<int> result;
    
    	int count = 0;
    
    	std::vector<char> buffer;
    
    	for(const auto& filename : filenames)
    	{
    		std::cout << (++count) << "/" << filenames.size() << "  \r" << std::flush;
    
    		std::ifstream stream(filename, std::ios_base::binary);
    		if(stream.is_open())
    		{
    			stream.seekg(0, std::ios_base::end);
    			const auto size = static_cast<size_t>(stream.tellg());
    			stream.seekg(0, std::ios_base::beg);
    
    			if(buffer.size() < size + 1)
    				buffer.resize(size + 1);
    
    			stream.read(buffer.data(), size);
    			buffer[size] = 0;
    		
    			const char *ptr = buffer.data();
    
    			while(*ptr != 0)
    			{
    				if(*ptr >= '0' && *ptr <= '9')
    				{
    					int value = *ptr - '0';
    					++ptr;
    					for(; *ptr >= '0' && *ptr <= '9'; ++ptr)
    						value = value * 10 + (*ptr - '0');
    
    					result.insert(value);
    				} else
    				{
    					++ptr;
    				}
    			}
    
    			if(bytesAnalyzed)
    				*bytesAnalyzed += size;
    		}
    	}
    
    	std::cout << std::endl;
    
    	return result;
    }

    Die gesuchten Ganzzahlen können dann im Ergebnisset gesucht werden was relativ schnell geht. Noch schneller wäre es vermutlich auch die gesuchten Zahlen in ein Set zu packen und mittels std::set_difference eine Liste der fehlenden Werte zu erhalten.

    Wenn Du mir obenstehende Fragen beantworten kannst (und ich nochmal Zeit finde) dann sehe ich mir das Thema gerne noch mal an.

    mfg

    Andreas

    Mittwoch, 8. Oktober 2014 09:00
  • Hallo Andreas

    Danke für die Tipps! Eine UTM Koordinate in unseren Breiten besteht aus einem 6 stelligen Längengrad und einem 7 stelligen Breitengrad wenn ich mit einer Genauigkeit von 1 m arbeite, also 5/6 stellige war schon mal eine zuwenig :-(

    Einige Zeilen einer der XML Dateien sieht also z.B. so aus

     <gml:posList>
               315603 5577753
               315609 5577754

     </gml:posList>

    Dann habe ich eine Datenbank mit 20 Mill Positionen desselben Aufbaus, jede davon soll in den XML Dateien gesucht werden, ohne XML Parser zu benutzen, weil der Aufbau der XML Struktur fehlerhaft ist.


    Freudi

    Mittwoch, 8. Oktober 2014 10:06