Yumekui Skrevet 8. juli 2012 Del Skrevet 8. juli 2012 (endret) Jeg har en (relativt stor) tekstfil som jeg deler opp i ord og genererer n-grammer av lengder fra og med 1 til og med n fra. Deretter lagrer jeg informasjon i rekker i to kolonner hvor den første kolonnen inneholder et ngram, og den andre kolonnen inneholder et ord som fulgte rett etter ngrammet i teksten. så "a a b c d e" for n = 2 blir da omtrent: Tabell 1: (a,) --> a (a,) --> b (b,) --> c (c,) --> d (d,) --> e Tabell 2: (a, a) --> b (a, b) --> c (b, c) --> d (c, d) --> e Problemet er at det tar litt vel lang tid å skrive til og lese fra denne databasen når den begynner å få litt lengde. Dersom jeg ikke har tenkt til å gjøre annet enn SELECT word FROM tablename WHERE ngram=? og INSERT OR IGNORE INTO tablename VALUES (?,?) Lønner det seg å ha flere databaser, for eksempel en database for hver bokstav målt etter hvilken bokstav det første elementet i hvert ngram har slik at hver databasefil blir mindre? Jeg antar her at det tar lang tid når databasen blir lang fordi den må dytte på så mye hver gang den skal legge til noe. Eller noe sånn. Endret 8. juli 2012 av Yumekui Lenke til kommentar
slacky Skrevet 8. juli 2012 Del Skrevet 8. juli 2012 (endret) Konstant skriving til databasen, og mange rader vil altid gjøre det tregere. I noen tilfeller kan det lønne seg å bruke faltfiler, men vet ikke om dette er ett av dem. mysql vil fort sluke mye ram når den er høyt belastet. Kunne gjerne tenkt meg at du spesifiserte litt mer om kolonnene, er det int, varchar, textarea etc, og størrelsen på disse er? Er det korte tekster burde størrelsen være helt minimal. Hvor langt mener du dette blir, og hvor mye pushes inn i løpet av kort tid har også en del å si. Du kan fort klare å gjøre databasen for treg etter 20,000 rader. Er det enkel data som skal catches så er vel ikke SQL den beste veien å gå. Uten noen som helst forståelse for hva dette gjelder så vil jeg bare notere: Jeg bruker av og til å jukse, dette er for å unngå at den må lese så utrolig mye (dette gjelder bare om en skal hente ut f.eks 500 rader samtidig). Du kan pakke mye data inn i en kolonne ved å seprarere data med div. tegn. for å så bruke split() når data er hentet ut. Det negatve er at det blir fort mer komplisert, og uoversiktelig. Endret 8. juli 2012 av warpie Lenke til kommentar
Yumekui Skrevet 8. juli 2012 Forfatter Del Skrevet 8. juli 2012 (endret) Hvert ngram er opprinnelig en Python-tuppel bestående av unicode strenger. Jeg omgjør hver tuppel til en streng før jeg legger de i den første kolonnen. Den andre kolonnen inneholder også strenger (ett enkelt ord per rad). Så hver rad er liten, men antallet rader kommer fort til å overstige 100 000. Det er ønskelig at jeg kan hente ut ordet i kolonne ved å bare vite ngrammet i kolonne 1 SELECT word FROM tablename WHERE ngram=? ordner dette for øyeblikket. Innholdet blir seende noe slikt ut: x = c.execute("Select * from table_name") for a in sorted(x): print a #----- ... (u"(u'a', u'$')", u'3') (u"(u'a', u'$')", u'400') (u"(u'a', u'.')", u'barret') (u"(u'a', u'.')", u'douglas') (u"(u'a', u'.')", u's') (u"(u'a', u'11%')", u'tax') (u"(u'a', u'14%')", u'average') (u"(u'a', u'2')", u',') ... (u"(u'a', u'way')", u'to') (u"(u'a', u'wealthy')", u'slave-holding') (u"(u'a', u'wedding')", u'was') (u"(u'a', u'while')", u',') (u"(u'a', u'wide')", u'spectrum') (u"(u'a', u'workforce')", u'of') (u"(u'a', u'year')", u'before') (u"(u'a', u'young')", u'west') (u"(u'aba', u')')", u',') ... (u"(u'about', u'0')", u'.') (u"(u'about', u'0\\xb0c')", u')') (u"(u'about', u'10%')", u'medical') (u"(u'about', u'10')", u':') (u"(u'about', u'120')", u',') (u"(u'about', u'15\\xb0c')", u'.') (u"(u'about', u'1\–2')", u'per') ... (u"(u'achilles', u'through')", u'his') (u"(u'achilles', u'to')", u'chiron') (u"(u'achilles', u'to')", u'heal') (u"(u'achilles', u'to')", u'their') (u"(u'achilles', u'was')", u'cremated') (u"(u'achilles', u'was')", u'once') (u"(u'achilles', u'was')", u'scaling') ... (u"(u'adequate', u'understanding')", u'of') (u"(u'adequate', u'yearly')", u'progress') (u"(u'aderholt', u',')", u'morris') (u"(u'adhered', u'to')", u'the') (u"(u'adherents', u'.')", u'a') (u"(u'adherents', u'in')", u'alabama') (u"(u'adhesion', u'.')", u'gene') (u"(u'adi-r', u')')", u'is') (u"(u'adjustments', u',')", u'or') (u"(u'administration', u',')", u'cabinet') (u"(u'administration', u'offered')", u'him') (u"(u'administrations', u'were')", u're-formed') (u"(u'admiration', u'of')", u'and') (u"(u'admission', u'of')", u'either') (u"(u'admitted', u'october')", u'31') (u"(u'admitted', u'to')", u'the') (u"(u'adolescence', u',')", u'but') (u"(u'adolescents', u'and')", u'adults') (u"(u'adopted', u'a')", u'constitution') (u"(u'adopted', u'the')", u'alphabet') (u"(u'adopted', u'the')", u'etruscan') (u"(u'adopting', u'a')", u'revolutionary') (u"(u'ados', u')')", u'uses') (u"(u'adtran', u',')", u'computer') (u"(u'adult', u'levels')", u'.') (u"(u'adult', u'onset')", u'diabetes') (u"(u'adult', u'residential')", u'programs') (u"(u'adulthood', u',')", u'although') (u"(u'adulthood', u',')", u'though') (u"(u'adults', u',')", u'10%') ... (u"(u'airport', u'(')", u'mob') (u"(u'airport', u'(')", u'msl') (u"(u'airport', u'(')", u'tcl') ... #(etc) Endret 8. juli 2012 av Yumekui Lenke til kommentar
Terrasque Skrevet 8. juli 2012 Del Skrevet 8. juli 2012 Hvordan er tabellene satt opp? Bruker du indeks og transaksjoner? Lenke til kommentar
Yumekui Skrevet 8. juli 2012 Forfatter Del Skrevet 8. juli 2012 (endret) Bruker indekser, ja - Jeg vet ikke om transaksjoner brukes eller ikke. Det er denne delen som tar lang tid i större databaser: query = u"INSERT OR IGNORE INTO {TABLENAME} VALUES (?,?)".format(TABLENAME=tablename) try: self.brain.execute(query, (ngram, word)) import sqlite3 class DiskFormat(object): """Fileformat is an SQLite database""" def load(self): self.conn = sqlite3.connect("@brain.db") self.brain = self.conn.cursor() self.MakeTables() def save(self, keepold=False): self.conn.commit() def _ExecuteMakeTable(self, tablename): self.brain.execute('''CREATE TABLE {name} (ngram text, word text)'''.format(name=tablename)) def _ExecuteMakeIndice(self, tablename): print "Creating unique index for:",tablename self.brain.execute('''CREATE UNIQUE INDEX ind_{name} ON {name} (ngram, word)'''.format(name=tablename)) def MakeTables(self): """Called to make sure enough tables to meet requirement of current n exist""" #keep track of ngrams up to and including this length n = config["ngrams"] for db in range(1, n+1): try: tablename = "precedes_{0}".format(db) self._ExecuteMakeTable(tablename) self._ExecuteMakeIndice(tablename) except sqlite3.OperationalError as sqlerr: if "already exists" in str(sqlerr): pass else: raise try: tablename = "succeeds_{0}".format(db) self._ExecuteMakeTable(tablename) self._ExecuteMakeIndice(tablename) except sqlite3.OperationalError as sqlerr: if "already exists" in str(sqlerr): pass else: raise def DB_Write(self, tablename, ngram, word): """Add word as related to ngram in table""" ngram = unicode(ngram) query = u"INSERT OR IGNORE INTO {TABLENAME} VALUES (?,?)".format(TABLENAME=tablename) try: self.brain.execute(query, (ngram, word)) pass except sqlite3.IntegrityError as interr: if "are not unique" in str(interr): pass else: raise Endret 8. juli 2012 av Yumekui Lenke til kommentar
FraXinuS Skrevet 10. juli 2012 Del Skrevet 10. juli 2012 Det ser ut som du bruker transaksjoner, men det spørs hvor ofte du kaller save(). Når du skriver til databasen prøv å kjør kanskje 1000-10000 DB_Write() mellom hver gang du kaller save(), prøv deg fram for å finne det riktige antallet. Det skal gjøre skrivingen en del raskere hvis du ikke allerede gjør det. Du kan kanskje også prøve å finne en bedre måte å lagre ngram verdien, nå er det veldig mye repeterende data med "(u'" i hver rad. Lenke til kommentar
Yumekui Skrevet 10. juli 2012 Forfatter Del Skrevet 10. juli 2012 Det ser ut som du bruker transaksjoner, men det spørs hvor ofte du kaller save(). Når du skriver til databasen prøv å kjør kanskje 1000-10000 DB_Write() mellom hver gang du kaller save(), prøv deg fram for å finne det riktige antallet. Det skal gjøre skrivingen en del raskere hvis du ikke allerede gjør det. Du kan kanskje også prøve å finne en bedre måte å lagre ngram verdien, nå er det veldig mye repeterende data med "(u'" i hver rad. Jeg kalte ikke save i det hele tatt, egentlig. Jeg gjorde det helt til slutt. Er det noe slik som for sjeldent? Ved ettertanke bruker jeg ikke ngrammene til noe annet enn å hente ut ordene, så jeg kan sikkert lagre de på en annen måte som for eksempel mellomrom-separerte verdier. Lenke til kommentar
Foxboron Skrevet 12. juli 2012 Del Skrevet 12. juli 2012 (endret) http://docs.python.org/library/sqlite3.html#sqlite3.Cursor.executemany Tror det er denne du trenger Endret 12. juli 2012 av JuletreDuden Lenke til kommentar
Yumekui Skrevet 20. juli 2012 Forfatter Del Skrevet 20. juli 2012 http://docs.python.org/library/sqlite3.html#sqlite3.Cursor.executemany Tror det er denne du trenger Det hjalp noe, men det går fremdeles tregere å tregere. Skal jeg bare dele databasen opp i flere filer? Lenke til kommentar
torbjørn marø Skrevet 21. juli 2012 Del Skrevet 21. juli 2012 Skal jeg bare dele databasen opp i flere filer? Det høres ut som en veldig dårlig ide. Hvor mye data er det vi snakker om? Og hvor tregt er tregt? Og hvor mange duplikater har du - dvs. hvor mange exceptions generer scriptet ditt? Lenke til kommentar
Yumekui Skrevet 21. juli 2012 Forfatter Del Skrevet 21. juli 2012 (endret) Hvor mye data er det vi snakker om? Og hvor tregt er tregt? Og hvor mange duplikater har du - dvs. hvor mange exceptions generer scriptet ditt? Datamengden er en tekstfil med et par millioner linjer (hver av setningene gjøres om til ngrammer) I begynnelsen går det rimelig raskt (1000 setninger i sekundet~), men ettersom databasen blir større og større går det tregere og tregere, og når antallet prosesserte setninger er oppe i 30000-50000 tar det 40~ sekunder for 1000 setninger. Tabellen succeeds_2 inneholder 2 066 156 rekker etter 40 000 setninger (av en eller annen grunn tar det lenger tid å fylle tabeller med ngrammer av større n-verdier). Jeg vet ikke hvordan det er med duplikatmengden. Jeg antar det blir flere og flere ettersom antallet entries øker. Lagde et ganske rotete skript for å mate linjer fra tekstfilen til programmet (i dette tilfellet 1000 og 1000 linjer av gangen), disse linjene gjøres om til ngrammer og puttes i en [(ngram, ord), (ngram, ord), ...] liste, og hele denne listen gis til executemany (så med mindre jeg tuller med noe skulle ikke for mange kall til execute være problemet) from engine import main import time def Learn3(bulk): L = [] i = 0 with open("learning/LineFile.txt") as f: for line in f: line = line.decode("utf8") line = line.strip() L.append(line) if len(L) == bulk: print "\ncurrent:",i i += bulk contents = " ".join(L) a = time.time() proc.QuickLearn(contents, "abc", "def") print bulk,"in:",time.time() - a L = [] #Do the last of L contents = " ".join(L) proc.QuickLearn(contents, "abc", "def") proc = main.Engine() Learn3(1000) braintf.save() Selve databasen lages og skrives til slik (det er den siste linjen, self.brain.executemany(u"INSERT OR IGNORE INTO {TABLENAME} VALUES (?,?)".format(TABLENAME=tablename), ngwl) som tar tid (og den tar lenger tid jo større n (antall ord i lengste ngram) blir)): class DiskFormat(object): """Fileformat is an SQLite database""" def load(self): dbpath = "database" + sep + "@brain.db" self.conn = sqlite3.connect(dbpath) self.brain = self.conn.cursor() self.MakeTables() def save(self, keepold=False): self.conn.commit() def _ExecuteMakeTable(self, tablename): self.brain.execute('''CREATE TABLE {name} (ngram text, word text)'''.format(name=tablename)) def _ExecuteMakeIndice(self, tablename): print "Creating unique index for:",tablename self.brain.execute('''CREATE UNIQUE INDEX ind_{name} ON {name} (ngram, word)'''.format(name=tablename)) def MakeTables(self): """Called to make sure enough tables to meet requirement of current n exist""" #keep track of ngrams up to and including this length n = config["ngrams"] for db in range(1, n+1): try: tablename = "precedes_{0}".format(db) self._ExecuteMakeTable(tablename) self._ExecuteMakeIndice(tablename) except sqlite3.OperationalError as sqlerr: if "already exists" in str(sqlerr): pass else: raise try: tablename = "succeeds_{0}".format(db) self._ExecuteMakeTable(tablename) self._ExecuteMakeIndice(tablename) except sqlite3.OperationalError as sqlerr: if "already exists" in str(sqlerr): pass else: raise def DB_Write(self, tablename, ngram_word_list): """Takes a list of ngram-word tuples and inserts them into &--#60;tablename&--#62; input: [(ngram, word), ...] """ ngwl = [(u" ".join(ngram), word) for ngram,word in ngram_word_list] #try: self.brain.executemany(u"INSERT OR IGNORE INTO {TABLENAME} VALUES (?,?)".format(TABLENAME=tablename), ngwl) """ except sqlite3.IntegrityError as interr: if "are not unique" in str(interr): pass else: raise """ Endret 21. juli 2012 av Yumekui Lenke til kommentar
FraXinuS Skrevet 22. juli 2012 Del Skrevet 22. juli 2012 Hvis du lar være å opprette indexen før du inserter dataen vil det mest sannsynlig gå en del raskere. Det er ikke sikkert det har noe å si om det blir satt inn noen duplikater, eller du kan prøve å fjerne dem etterpå. 1 Lenke til kommentar
Yumekui Skrevet 22. juli 2012 Forfatter Del Skrevet 22. juli 2012 Hvis du lar være å opprette indexen før du inserter dataen vil det mest sannsynlig gå en del raskere. Det er ikke sikkert det har noe å si om det blir satt inn noen duplikater, eller du kan prøve å fjerne dem etterpå. Det ser ut til å ha hjulpet. Ganske konstant skrivehastighet nå etter hva jeg kan se. Duplikater har noe å si, men det burde gå greit å fjerne disse i ettertid. Lenke til kommentar
Yumekui Skrevet 22. juli 2012 Forfatter Del Skrevet 22. juli 2012 Men uten indeks tar lesing fra databasen en evighet. Lenke til kommentar
FraXinuS Skrevet 22. juli 2012 Del Skrevet 22. juli 2012 Du kan legge inn indexen etterpå. Men hvis du har duplikater så kan du ikke legge inn en unique index, bare en vanlig index. Lenke til kommentar
torbjørn marø Skrevet 22. juli 2012 Del Skrevet 22. juli 2012 (endret) Du kan legge inn indexen etterpå. Men hvis du har duplikater så kan du ikke legge inn en unique index, bare en vanlig index. Dette er en helt vanlig strategi ved batch-oppdatering av data - fjerne index, gjøre masse endringer, og så bygge indexene på nytt. Fungerer bra sålenge dataene ikke samtidig skal være tilgjengelige for spørringer Endret 22. juli 2012 av torbjørn marø Lenke til kommentar
Yumekui Skrevet 22. juli 2012 Forfatter Del Skrevet 22. juli 2012 (endret) Er det noen grei måte å fjerne duplikatrekker etterpå? Endret 22. juli 2012 av Yumekui Lenke til kommentar
torbjørn marø Skrevet 22. juli 2012 Del Skrevet 22. juli 2012 (endret) Er det noen grei måte å fjerne duplikatrekker etterpå? Snakker vi om Sqlite 3 (og det gjør vi jo) skal du kunne kjøre: DELETE FROM table WHERE rowid NOT IN (SELECT MAX(rowid) FROM table GROUP BY ngram); Endret 22. juli 2012 av torbjørn marø Lenke til kommentar
Terrasque Skrevet 31. juli 2012 Del Skrevet 31. juli 2012 (endret) http://stackoverflow...mance-of-sqlite Her er et par tips til å øke sqlite ytelse. Ser du enda ikke har lagt inn transactions, for eksempel. Edit: Ah, transactions er lagt inn, my bad Endret 31. juli 2012 av Terrasque Lenke til kommentar
Anbefalte innlegg
Opprett en konto eller logg inn for å kommentere
Du må være et medlem for å kunne skrive en kommentar
Opprett konto
Det er enkelt å melde seg inn for å starte en ny konto!
Start en kontoLogg inn
Har du allerede en konto? Logg inn her.
Logg inn nå