Ho asked a simlar question on Meta Stack Overflow, ma si occupa specificamente se lo Lucene.NET è utilizzato o meno su Stack Overflow.Come utilizzare Lucene.NET per implementare la ricerca in un sito come Stack Overflow?
Lo scopo della domanda qui è più di un ipotetico, in quanto a ciò che si avvicina si potrebbe fare se dovessero usare Lucene.NET come base per in-sito di ricerca e di altri fattori in un sito come Stack Overflow [SO].
Come per l'entrata sul Stack Overflow blog dal titolo "SQL 2008 Full-Text Search Problems" c'è stata una forte un'indicazione che Lucene.NET stata presa in considerazione a un certo punto, ma sembra che non è sicuramente il caso, come per il commento da Geoff Dalgas il 19 febbraio 2010:
Lucene.NET non viene utilizzato per Stack Overflow - stiamo usando indicizzazione full-text di SQL Server. La ricerca è un'area dove continuiamo a fare piccole modifiche .
Quindi la mia domanda è: come si può utilizzare Lucene.NET in un sito che ha la stessa semantica di Stack Overflow?
Ecco alcuni retroscena e quello che ho fatto/pensiero circa fino ad ora (sì, ho attuato la maggior parte di questo e di ricerca è la ultimo aspetto che devo completare):
Technologies:
E, naturalmente, la stella dello spettacolo, Lucene.NET.
L'intenzione è anche di passare a .NET/C# 4.0 al più presto. Mentre non penso che sia un punto di svolta, dovrebbe essere notato.
Prima di entrare in aspetti di Lucene.NET, è importante sottolineare gli aspetti di SQL Server 2008, così come i modelli coinvolti.
modelle
Questo sistema ha più di un tipo di modello primario in confronto a Stack Overflow . Alcuni esempi di questi modelli sono:
- Domande: Queste sono domande che le persone possono chiedere. Le persone possono rispondere alle domande, proprio come su Stack Overflow.
- Note: si tratta di proiezioni unidirezionali, quindi in opposizione a una domanda si sta facendo una dichiarazione sul contenuto. Le persone non possono inviare risposte a questo.
- Eventi: si tratta di dati relativi a un evento in tempo reale. Ha informazioni sulla posizione, informazioni su data/ora.
La cosa importante da notare su questi modelli:
- Essi hanno tutti un/titolo (testo) proprietà Name e un corpo (HTML) immobili (i formati sono irrilevanti, come il contenuto sarà analizzato in modo appropriato per l'analisi).
- Ogni istanza di un modello ha un URL univoco sul sito
Poi ci sono le cose che Stack Overflow prevede che IMO, sono decoratori ai modelli. Questi decoratori possono avere diverse cardinalità, sia essendo uno-a-uno o uno-a-molti:
- voti: calettata sull'utente
- Risposte: facoltativa, ad esempio, vedere il caso note sopra
- Preferito: il modello è elencato come preferito di un utente?
- Commenti: (facoltativo)
- Associazioni di tag: i tag si trovano in una tabella separata, in modo da non replicare il tag per ciascun modello. Esiste un collegamento tra il modello e la tabella delle associazioni dei tag e quindi dalla tabella delle associazioni dei tag alla tabella dei tag.
E ci sono conteggi di sostegno che di per sé sono uno-a-uno decoratori ai modelli che sono calettate a loro nello stesso modo (solitamente da un tipo di modello id e il modello id):
- Voti di voto: totale postivi, voti negativi, Wilson Score interval (questo è importante, determinerà il livello di confidenza basato sui voti per una voce, per la maggior parte, assume il limite inferiore dell'intervallo Wilson).
Le risposte (risposte) sono modelli che hanno la maggior parte dei decoratori della maggior parte dei modelli, non hanno un titolo o un URL e se un modello ha una risposta è opzionale. Se le risposte sono permesse, è ovviamente una relazione uno-a-molti.
SQL Server 2008
Le tabelle più o meno seguire il layout dei modelli di cui sopra, con tavoli separati per i decoratori, così come alcune tabelle di supporto e le viste, stored procedure, ecc
Va notato che la decisione di non utilizzare la ricerca full-text si basa principalmente sul fatto che non normalizza i punteggi come Lucene.NET. Sono aperto a suggerimenti su come utilizzare la ricerca basata su testo, ma dovrò eseguire ricerche su più tipi di modelli, quindi tieni presente che dovrò normalizzare il punteggio in qualche modo.
Lucene.NET
Questo è dove il grande punto interrogativo è. Ecco i miei pensieri fino ad ora su Stack Funzionalità di overflow, nonché come e cosa ho già fatto.
indicizzazione
Domande/Modelle
Credo che ogni modello dovrebbe avere un indice della propria contenente un ID univoco per cercare rapidamente in su sulla base di un'istanza termine di quella id (indicizzato , non analizzato).
In quest'area, ho considerato che Lucene.NET analizza ogni domanda/modello e ogni risposta individualmente. Quindi, se c'erano una domanda e cinque risposte, la domanda e ciascuna risposta sarebbero state indicizzate come un'unità separata.
L'idea qui è che il punteggio di pertinenza che Lucene.NET restituisce sarebbe più facile confrontare tra modelli che proiettano in modi diversi (ad esempio, qualcosa senza risposte).
Ad esempio, una domanda imposta il soggetto, quindi la risposta elabora sull'argomento.
Per una nota, che non ha risposte, gestisce la questione di presentare il soggetto e quindi di elaborarlo.
Credo che ciò contribuirà a rendere i punteggi di pertinenza più pertinenti l'uno con l'altro.
Tag
Inizialmente, ho pensato che questi dovrebbero essere tenuti in un indice separato con più campi che hanno gli ID ai documenti nell'indice modello appropriato. Oppure, se è troppo grande, c'è un indice con solo i tag e un altro indice che mantiene la relazione tra l'indice dei tag e le domande a cui sono applicati. In questo modo, quando si fa clic su un tag (o utilizzare la struttura degli URL), è facile vedere in maniera progressiva che è sufficiente "buy in", se ci riesci:
- Se la variabile esiste
- quali domande i tag sono associati con
- le domande stesse
Tuttavia, in pratica, facendo una query di tutti gli elementi in base al tag (come clic su un tag in modalità Stack overflow) è estremamente facile con SQL Server 2008. Sulla base del modello di cui sopra, si richiede semplicemente una ricerca del tipo:
select
m.Name, m.Body
from
Models as m
left outer join TagAssociations as ta on
ta.ModelTypeId = <fixed model type id> and
ta.ModelId = m.Id
left outer join Tags as t on t.Id = ta.TagId
where
t.Name = <tag>
E dal momento che alcune proprietà sono condivisi tra tutti i modelli, è abbastanza facile da fare un UNION
tra i diversi modelli tipi/tavoli e produrre un insieme coerente di risultati.
questo sarebbe analogo a un TermQuery
in Lucene.NET (sto riferimento al Java documentation dal momento che è completo, e Lucene.NET è pensato per essere una traduzione linea per linea di Lucene, quindi tutta la documentazione è il stesso).
Il problema che si presenta con l'uso di Lucene.NET è quello dell'ordine. Il punteggio di pertinenza per un TermQuery quando si tratta di tag è irrilevante. È o 1 o 0 (o ce l'ha o no).
A questo punto, il punteggio di confidenza (Wilson intervallo di punteggio) entra in gioco per ordinare i risultati.
Questo punteggio può essere memorizzato in Lucene.NET, ma per ordinare i risultati su questo campo, farebbe affidamento sui valori memorizzati nella cache di campo, che è qualcosa che davvero, davvero voglio evitare. Per un gran numero di documenti, la cache di campo può diventare molto grande (il punteggio di Wilson è doppio e occorrerebbe un doppio per ogni documento, che può essere un unico array).
Dato che posso cambiare l'istruzione SQL per ordine basato sul Wilson segnare intervallo di simile a questo:
select
m.Name, m.Body
from
Models as m
left outer join TagAssociations as ta on
ta.ModelTypeId = <fixed model type id> and
ta.ModelId = m.Id
left outer join Tags as t on t.Id = ta.TagId
left outer join VoteTallyStatistics as s on
s.ModelTypeId = ta.ModelTypeId and
s.ModelId = ta.ModelId
where
t.Name = <tag>
order by
--- Use Id to break ties.
s.WilsonIntervalLowerBound desc, m.Id
Sembra una scelta facile da usare questo per gestire il pezzo di Stack funzionalità Overflow "get tutti gli articoli contrassegnati con <tag> ".
Risposte
In origine, ho pensato che questo è un indice separato propria, con una chiave di nuovo nell'indice domande.
penso che ci dovrebbe essere una combinazione di ogni modello e ogni risposta (se ce n'è uno) in modo che la pertinenza punteggi per i diversi modelli sono più "uguale" rispetto gli uni agli altri.
Questo ovviamente gonfierà l'indice. Sono un po 'a mio agio in questo momento.
Oppure, c'è un modo per memorizzare per esempio, i modelli e le risposte come documenti individuali in Lucene.NET e poi prendere entrambi e in grado di ottenere la pertinenza valutazione per una query trattamento entrambi i documenti come uno? Se è così, questo sarebbe ideale.
Ciè, naturalmente, la questione di ciò che i campi saranno memorizzati, indicizzato, analizzato (tutte le operazioni possono essere distinte operazioni, o mix-and-matched)? Quanto sarebbe un indice?
Cosa succede ad usare speciali stemmer/facchini per errori di ortografia (utilizzando Metaphone), così come sinonimi (c'è la terminologia nella comunità sarò servizio che ha il proprio gergo/terminologia per certe cose che ha molteplici rappresentazioni)?
Boost
Questo è legato alla indicizzazione, naturalmente, ma penso che meriti è propria sezione.
Sei incrementando i campi e/o documenti? Se sì, come li potenzia? La costante di boost per determinati campi? Oppure viene ricalcolata per i campi in cui è applicabile la votazione/visualizzazione/preferiti/dati esterni.
Per esempio, nel documento, non il titolo ottiene una spinta su tutto il corpo? Se sì, quali fattori di spinta pensi che funzionino bene? E i tag?
L'idea qui è la stessa che è lungo le linee di Stack Overflow . I termini nel documento hanno rilevanza, ma se un documento è taggato con il termine, o è nel titolo, allora dovrebbe essere potenziato.
Shashikant Kore suggerisce una struttura documento come questo:
- Titolo
- Domanda
- risposta accettata (o rispondere altamente votato se non c'è risposta accettata)
- Tutte le risposte combinato
E quindi utilizzare boost ma non basato sul valore di voto non elaborato. Credo di avere quello coperto dall'intervallo Wilson Score.
La domanda è: dovrebbe essere applicata la spinta all'intero documento? Sono inclinato verso il no su questo, perché significherebbe che dovrei reindicizzare il documento ogni volta che un utente ha votato il modello.
Ricerca articoli Tagged
Ho inizialmente pensato che durante la ricerca di un tag (da specificamente cliccando su uno o utilizzando la struttura di URL per la ricerca di contenuti con tag), che è un semplice TermQuery contro l'indice di tag per il tag, quindi nell'indice delle associazioni (se necessario), quindi torna alle domande, Lucene.NET gestisce questo molto rapidamente.
Tuttavia, date le note di cui sopra su quanto sia facile farlo in SQL Server, ho optato per quella rotta quando si tratta di cercare elementi contrassegnati.
Generale Ricerca
Così ora, la questione più rilevante è quando si fa una frase generale o di ricerca termine contro i contenuti, che cosa e come si fa a integrare altre informazioni (ad esempio voti) al fine di determinare i risultati nell'ordine corretto? Ad esempio, durante l'esecuzione di questa ricerca su ASP.NET MVC on Stack Overflow, questi sono i conteggi per i primi cinque risultati (quando si utilizza la scheda rilevanza):
q votes answers accepted answer votes asp.net highlights mvc highlights
------- ------- --------------------- ------------------ --------------
21 26 51 2 2
58 23 70 2 5
29 24 40 3 4
37 15 25 1 2
59 23 47 2 2
Si noti che i punti salienti sono solo nel titolo e astratta nella pagina dei risultati e sono solo lievi indicatori di ciò che la vera frequenza di termine è nel documento, titolo, tag, risposta (tuttavia sono applicati, che è un'altra buona domanda).
Come tutto questo ha riunito?
A questo punto, so che Lucene.NET restituirà un punteggio di pertinenza normalizzato, ei dati di voto mi forniranno un intervallo di punteggio Wilson che posso utilizzare per determinare il punteggio di confidenza.
Come devo considerare la combinazione di questi due punteggi per indicare l'ordinamento del set di risultati in base alla pertinenza e alla sicurezza?
E 'ovvio per me che ci dovrebbe essere un po' rapporto tra i due, ma quello che il rapporto dovrebbe essere me sfugge a questo punto. So che devo perfezionarlo col passare del tempo, ma sono davvero perso su questa parte.
miei pensieri iniziali sono se la pertinenza valutazione è beween 0 e 1 e il punteggio di confidenza è compreso tra 0 e 1, quindi ho potuto fare qualcosa di simile:
1/((e^cs) * (e^rs))
In questo modo, si ottiene un valore normalizzato quello che si avvicina a 0 è il più pertinente e sicuro del risultato, e può essere risolto su quello.
Il problema principale è che se l'incremento viene eseguito sul tag eo sul campo titolo, il punteggio di pertinenza è fuori dai limiti da 0 a 1 (il limite superiore diventa illimitato quindi, e non so come trattare con quello).
Inoltre, credo che dovrò aggiustare il punteggio di confidenza per tenere conto delle valutazioni di voto che sono completamente negative. Dal momento che il voto indica risultati completamente negativi in un intervallo di punteggio Wilson con un limite inferiore di 0, qualcosa con -500 voti ha lo stesso punteggio di confidenza di qualcosa con -1 voto o 0 voti.
Fortunatamente, il limite superiore diminuisce da 1 a 0 mentre i valori di voto negativi salgono. Potrei cambiare il punteggio di confidenza per essere un intervallo tra -1 e 1, in questo modo:
confidence score = votetally < 0 ?
-(1 - wilson score interval upper bound) :
wilson score interval lower bound
Il problema di questo è che collegare 0 nell'equazione è di grado tutti gli elementi con zero voti inferiori a quelli con voti negativi.
A tal fine, sto pensando se il punteggio di confidenza verrà utilizzato in un'equazione reciproca come sopra (sono ovviamente preoccupato per l'overflow), quindi deve essere rielaborato per essere sempre positivo. Un modo per ottenere questo risultato è:
confidence score = 0.5 +
(votetally < 0 ?
-(1 - wilson score interval upper bound) :
wilson score interval lower bound)/2
mie altre preoccupazioni sono come eseguire in realtà il calcolo data Lucene.NET e SQL Server. Sono riluttante a mettere il punteggio di confidenza nell'indice di Lucene perché richiede l'uso della cache di campo, che può avere un enorme impatto sul consumo di memoria (come menzionato prima).
un'idea che ho avuto è stato quello di ottenere la pertinenza valutazione da Lucene.NET e quindi utilizzando un table-valued parameter per lo streaming il punteggio di SQL Server (insieme con gli ID degli elementi da selezionare), a quel punto mi piacerebbe effettuare le calcolo con il punteggio di confidenza e quindi restituire i dati correttamente ordinati.
Come affermato in precedenza, ci sono molte altre domande che ho su questo, e le risposte hanno iniziato a inquadrare le cose, e continuerò ad espandere le cose man mano che la domanda e le risposte vengono eluse.
@Paul: Ho aggiornato la domanda per riflettere su come i dati di voto (che è un punteggio di confidenza) si riferiscono al punteggio di pertinenza e pensieri sulle risposte. Non credo che userò la reputazione dell'utente per soppesare i risultati di ordinamento della ricerca, ma in termini di risposte di spareggio in termini di voti, è abbastanza facile da fare in SQL Server. – casperOne