Newsgroup: it.comp.lang.visual-basic
Titolo: [?] Ricerca full text su gruppi di files [LUNGO]

Saluti a tutti :-)
Ho bisogno di qualche consiglio per un problema rognoso...
Mi trovo nella necessità di poter effettuare delle ricerche full-text
su un gruppo di documenti alla volta; il limite massimo è di un paio
di migliaia. In effetti si tratta di svariati doc in PDF, dai quali
estraggo il testo con una utility in DOS.
La ricerca deve essere effettuata quindi sui file txt generati, salvo
poi avere una tabella di corrispondenza. Ovviamente non è proponibile
cercare ogni volta sui file di testo, e non ho la possibilità di usare
un database (le specifiche sono queste... il prog deve poter andare su
macchine di tutti i tipi, sacrificando se necessario la velocità).
Aggiungo che non posso usare l'indicizzazione dei file PDF di Acrobat,
per una serie di motivi.
In seguito a qualche consiglio (grazie, Gigio :-) ) e un certo sforzo
del mio povero neurone, sono arrivato ad una soluzione, che però non è
certo ottimale, al massimo la si potrebbe definire funzionante :-)
La spiego a grandi linee; se qualcuno ha idee per migliorare il tutto,
mi fa un favore.
Premessa: non mi interessa se la fase di preparazione dell'indice è
lenta, posso metterci anche un giorno di tempo macchina, volendo.
Mi interessa di più lo spazio su disco e la velocità di ricerca.
Ah, i limiti richiesti sono: max 64K parole, max 2K files.
NON devo ritrovare la posizione della parola all'interno del file,
ma solo controllare se è presente.
Ho pensato di utilizzare una matrice di byte, in modo che ogni bit
della matrice mi faccia da boolean per verificare la presenza o meno
della parola in quella pagina... forse mi spiego meglio così:
dim NomiDiFiles (2048) as string ' indirizzi fisici dei files su disco.
Dim Parola(65536) As String ' elenco parole diverse; eliminate
' tutte le stringhe solo numeriche, e le parole di solo 2 o 3 lettere
' con alcune eccezioni.
Dim IndiceParola(65536) As Integer' ordine in cui è stata trovata
' la parola, fa da indice per trovare il record di cui sotto:
type MatriceFile
 ParolaInFile(512) as Byte
end type
Il funzionamento sarebbe questo: immaginate una matrice di parole
tipo la seguente:
Parola  Ordine in cui sono state trovate nei testi
abaco   145
abbaia   345
accalappiacani  367
..
occhiali 986
..
..
Zanzibar  267
Quando cerco nell'indice (con una ricerca ad albero binario,
quindi con al massimo sedici tentativi) la parola voluta,
uso l'indice associato come puntatore alla matrice dei file,
che tengo su disco, in modo da fare una semplice Seek e andare
direttamente al record giusto. Per fare un esempio, se sto
cercando la parola "occhiali"trovandola ottengo il puntatore 986;
Apro il file della matrice delle pagine, e prendo il record
986: lo analizzo,prima byte per byte (facendo un ciclo di 512
"If byte(X) = 0") in modo da controllare rapidamente un gruppo
di pagine, se è <> 0 ho trovato almeno una corrispondenza e
quindi scendo a livello del singolo bit. A questo punto, dove
trovo un bit a 1, ho trovato una pagina che contiene la parola;
il nome del file sarà dato dalla posizione del bit (numero del
byte * 8, più la posizione del bit nel byte) nella matrice di
bytes, che a sua volta fa da indice nella matrice dei files.
*******************
Se siete arrivati fin qui, e ci avete capito qualcosa, può essere
dovuto al fatto che avete un Q.I. molto elevato, provate a fare i
test del Mensa :-), poi andate avanti :-)))
*******************
In questo modo tengo in memoria solo le due matrici relativamente
piccole, lasciando su disco, e senza bisogno di ordinarlo, il file
più pesante. In più ho una ricerca abbastanza veloce.
Gli svantaggi della cosa sono pricipalmente due: il meno importante
è quello della complessità e della lentezza nella costruzione degli
indici, anche perchè devo fare una ricerca e eventualmente due insert
sorting ad ogni parola rilevata, nonché l'aggiornamento della matrice
dei files. Il principale è che a seconda del numero di parole diverse
realmente trovate nei file, la matrice parole/files può arrivare ad
occupare 32 mega :-(, perché per ogni parola, devo prevedere 512
bytes.
E' vero che accedo direttamente ad un record specifico con una seek,
ma la cosa non mi piace molto.
In breve: qualche suggerimento per migliorare l'ambaradan ?
P.S.: Scusate se trovate delle incongruenze, ma a quest'ora...
Bye, G.
--
Le risposte alle tue domande sono sul Sito Comune
di questo NewsGroup: 
http://it-lang-vb.net/
... e nell'help in linea !

 In breve: qualche suggerimento per migliorare l'ambaradan ?
Sě, utilizzare Berkeley DB (
http://www.sleepycat.com
)...
Dovresti verificare un paio di cose, ma l'utilizzo di questo
*non* č in contrasto con le specifiche che sono richieste,
perché č un *embedded* db, ovvero non si tratta di
un'applicazione esterna, ma di funzioni di una (o al limite piů)
dll da richiamare dal tuo codice (e quindi semplicemente da
ridistribuire assieme ad esso). Quello che devi verificare č che
sia utilizzabile da VB (ma č facilmente creabile un wrapper in
C) ed il costo, perché č gratuito per applicazioni che non sono
ridistribuite (e questo non č il tuo caso) e per sw open source.
Ciao.
-- 
BSD is for UNIX lovers -- linux is for Windows haters.

 ma la cosa non mi piace molto.
Non ho ben capito il concetto di pagine e di files. Se davvero non vuoi
mantenere dove una parola si trovi nel file, ma solo se il file la contiene,
ti basta adottare il tuo stesso metodo ai files e non alle loro pagine. Se,
invece, vuoi anche separare e gestire le pagine di un file (ma non hai detto
quante possono essere al max  le pagine di un file) potresti, lasciando il
tutto com'è, aggiungere un livello, parola/files, appunto, e tenere in
memoria solo questo (da cui, poi, risalire al file o, se c'è un
sottolivello, alla pagina del file).
Se non ho sbagliato i conti e escludendo la dimensione della parola, ti
bastano 250 bytes aggiuntivi per ogni parola che ti consentono di esprimere
(250*8)=2000 bits, pari al numero massimo di files previsti. 64000 parole *
250 bytes per parola)= 16M, quindi la metà di quei 32M che ti preoccupano. A
questo occorre ovviamente sommare (meglio se in altro vettore con stringhe a
dimensione variabile per contenerne le occupazioni in memoria) i bytes pari
al numero max di crt previsti per parola (supponiamo 20) più un numerello
(da 1 a 64000, rapportabile a un intero se sfrutti la parte
negativa -32768+32767) che ti rimanda, per ogni parola, al corrispondente
elemento dei 250 bytes prima descritti che si riferisce alla specifica
parola. Quindi un totale di max 64000*(16+2)=1M abbondante. Se prevedi di
aggiungere anche un numerello che ti indica il numero delle ricorrenze per
ogni parola, si arriva a 64000*(16+2+2)=1,28M
Col tuo stesso metodo, cerchi la parola, se trovata ne recuperi il puntatore
relativo e scandagli i 250 bytes (che rappresentano ciascuno un gruppo di 8
files). Quando il byte non è nullo, scendi a livello di bit e arrivi al file
specifico. Da qui può fare una ricerca analoga sulle pagine di quel file,
ovvero su una struttura a bits dove ogni bit rappresenta una pagina di
quello specifico file.
PS: Ho fatto una cosa del genere (la velocità non era però per niente
considerata, trattandosi di un'elaborazione "cotta e mangiata") per la tesi
di un'amica, basata fortemente sugli articoli di un certo periodo di alcuni
quotidiani nazionali. Lo scopo (i cui risultati salienti sono stati poi
messi in appendice) era proprio quello di trovare il numero delle ricorrenze
delle parole, ordinato sia per parola/ricorrenze che per ricorrenze/parola.

 al numero max di crt previsti per parola (supponiamo 20) piů un numerello
Beh, ho supposto 20 ma poi ho conteggiato con un 16... ;-)

 Sì, utilizzare Berkeley DB (
http://www.sleepycat.com
)...
Grazie mille, adesso lo vado a vedere. Per quanto riguarda la licenza,
il SW per ora è per uso interno della ditta. Penso sia comunque da
considerare commerciale, perché non è per uso "personale"... ma
non credo che farebbero storie a pagarlo, ammesso che sia una
licenza una tantum, royalty-free, insomma.
Questo perché è vagamente possibile che in futuro vada ridistribuito
su larga scala. Me lo leggo :-)
Bye, G.

 delle parole, ordinato sia per parola/ricorrenze che per ricorrenze/parola.
Quasi TANA :-)  E' un archivio delle pagine del giornale, in formato PDF,
ordinato per data ovviamente, e al quale devo aggiungere la funzionalità
di ricerca testo nell'ambito di ogni mese.
Bye, G.

 capire... posso "comprimere" meglio di come pensavo  :-)
Sě, questa č l'unico possibile suggerimento che volevo darti: Consumare 250
bytes per i riferimenti ai file (o pagine che dir si voglia) invece di 512.
250bytes * 8bits = 2000 che dovrebbe essere il massimo ;-)

 funzionalità di ricerca testo nell'ambito di ogni mese.
sai cosa pensavo ... se la ricerca e' per poche parole ( diciamo 5 )
potresti creare un dizionario parola per parola ( amaca.dat albero.dat
ecc... ) io pensavo alla struttura del file in questo modo ( per ottimizzare
la grandezza dei file e per far prendere una logica ai bit del file )
Amaca.dat
<blocco1> 10111100101...</bloco1>  - 53bit - 7byte
// contiene 53 bit che rappresentano le settimane dell'anno
l' LSB e' la 53° settimana dell'anno e l'MSB la prima cosi da avere l'ordine
da sx a dx
<blocco2>1010010</blocco2> - 7bit - 1byte
qui i bit sono i giorni della settimana da lunedi a domenica
esempio : la parola amaca e' presente LU, ME,SA
ora rimane il blocco per definire in quale dei 50~ articoli giornalieri e'
presente
<blocco3> come blocco1 dove al posto delle settimane metti l'articolo -
50bit - 7byte
cosi ti servono 50bit per ogni giorno ovvero 2281 Kb per le occorrenze di
Amaca su tutti gli articoli del 2003 e soli  187K per le occorrenze mensili
(scegli tu )
ora le parole hai detto che sono 64'000 ? azz 1,4Gb per tutto il vocabolario
mensile (MASSIMO) :-/ e' troppo ? pero' conta che cosi se ricerchi :
"Amaca bianca" leggerai il file di 187K di amaca , nel blocco 1 sai in quale
settimana e' presente passi al blocco 2 e sai che ci sono solo 3 righe da
leggere ( e' presente negli articoli di lunedi , martedi e sabato solo nella
prima settimana del mese ) quindi leggerai i 50bit per ognuno dei 3 gg e li
salvi su file
quindi in memoria avrai letto solo un file di massimo 187K e avrai messo i
risultati in un file che e' di soli 21K
ora i risultati saranno tipo :
Settimana1
    giorno1
        (dati) articolo 1,3,27 e 32
    giorno2
        (dati) articolo 5,45,46 ...
quindi con una tabella comparativa risali al nome del articolo n3 del
giorno1 della settimana 1 .
scusa tutto il giro e il casino , ma facendo 2 conti ti conviene secondo me
usare questo sistema perche' cosi i file sono compressi gia' automaticamente
nel momento in cui li indicizzi , ovvero :
Supercalifragilisti....dat (dati convertiti in bit per una facile lettura)
-----
100100~000 (54bit)
-----
010010 (7bit)
010000
---------
00000010000~0000 (50bit)
00000010000~0000
00000010000~0000
---EOF----
totale file =  54+7+7+50+50+50 = 218bit = 43K
Scusa tutto il casino ma dimmi , ti prego, che hai capito almeno il senso
!?!?!?!?
-- 
<Gigio2K>
Sito Comune
Nokia -> I.T.H.N. -> 
http://www.ithn.it/
VB -> I.C.L.VB -> 
http://www.it-lang-vb.net/

 !?!?!?!?
LOL... non ancora :-), ma ho solo dato un'occhiata, adesso rileggo
con calma.
Bye, G.

 con calma.
Hai avuto + di 12ore di tempo , dimmi che ci hai capito qualcosa, altrimenti
(rullo di tamburi) TE LO RISPIEGO !!!  <g>

 (rullo di tamburi) TE LO RISPIEGO !!!  <g>
LOL
Ho avuto un server piantato e non č stato divertente. Per
fortuna era un backup, non un primario. Ora ho due giorni
di riposo, me lo stampo e me lo leggo con calma, e ci
risentiamo giovedě ;-)))
P.S.: nel frattempo sono cambiate le specifiche....
raddoppiano le pagine, 4096 :-(((((((((((
Bye, G.

 raddoppiano le pagine, 4096 :-(((((((((((
fa nulla , se capisci quello che ho scritto non hai problemi a parlare in
linguaggio macchina !


 linguaggio macchina !
LOL
Bye, G.