Domanda

usando Hibernate ricerca annotazioni (per lo più solo @Field(index = Index.TOKENIZED)) Ho indicizzato un certo numero di settori relativi ad una classe persistente di mine chiamato Compound. I'VE di ricerca messa a punto del testo su tutti i campi indicizzati, utilizzando il MultiFieldQueryParser , che ha finora funzionato bene.

Tra i campi indicizzati e ricercabili è un campo chiamato CompoundName, con valori di esempio:

  • 3-Hydroxyflavone
  • 6,4'-Dihydroxyflavone

Quando cerco uno di questi valori in pieno le relative istanze composti vengono restituiti. Tuttavia i problemi si verificano quando si utilizza il nome parziale e presento i caratteri jolly:

  • alla ricerca di 3-Hydroxyflav* dà ancora il colpo corretto, ma
  • alla ricerca di 6,4'-Dihydroxyflav* non riesce a trovare nulla.

Ora come io sono abbastanza nuovo per Lucene / Hibernate-ricerca, non sono abbastanza sicuro dove andare a cercare, a questo punto .. penso che potrebbe avere qualcosa a che fare con la ' presente nella seconda query, ma io non so come procedere .. devo cercare in tokenizers / analizzatori / QueryParsers o qualcosa di completamente diverso?

O qualcuno può dirmi come posso ottenere la seconda ricerca con caratteri jolly per abbinare, preferibilmente senza rompere il comportamento multicampo-ricerca?

Sto usando Hibernate-Search & 3.1.0.GA Lucene-core 2.9.3.


Alcuni bit di codice rilevanti per illustrare il mio approccio attuale:

parti rilevanti della classe Compound indicizzato:

@Entity
@Indexed
@Data
@EqualsAndHashCode(callSuper = false, of = { "inchikey" })
public class Compound extends DomainObject {
    @NaturalId
    @NotEmpty
    @Length(max = 30)
    @Field(index = Index.TOKENIZED)
    private String                  inchikey;

    @ManyToOne
    @IndexedEmbedded
    private ChemicalClass           chemicalClass;

    @Field(index = Index.TOKENIZED)
    private String                  commonName;
...
}

Come Attualmente la ricerca sui campi indicizzati:

String[] searchfields = Compound.getSearchfields();
MultiFieldQueryParser parser = 
    new MultiFieldQueryParser(Version.LUCENE_29, searchfields, new StandardAnalyzer(Version.LUCENE_29));
FullTextSession fullTextSession = Search.getFullTextSession(getSession());
FullTextQuery fullTextQuery = 
    fullTextSession.createFullTextQuery(parser.parse("searchterms"), Compound.class);
List<Compound> hits = fullTextQuery.list();
È stato utile?

Soluzione

Credo che il problema è una combinazione di problemi dell'analizzatore e del linguaggio di interrogazione. E 'difficile dire che cosa causa esattamente il problema. Per scoprirlo vi consiglio di ispezionare indice utilizzando lo strumento dell'indice Lucene Luca .

Dal momento che nella configurazione Hibernate Search non si utilizza un analizzatore personalizzata di default - StandardAnalyzer - viene utilizzato. Ciò sarebbe coerente con il fatto che si usa StandardAnalyzer nel costruttore di MultiFieldQueryParser (utilizzare sempre lo stesso analizzatore per l'indicizzazione e la ricerca!). Quello che non sono così sicuro di è come "6,4'-Dihydroxyflavone" viene formato token da StandardAnalyzer . Che la prima cosa che dovete sapere. Ad esempio, il javadoc dice:

  

Divide parole a trattini, a meno che non   c'è un numero nel token, in   tal caso tutto il token è   interpretato come numero prodotto ed è   Non scissione.

Potrebbe essere che è necessario scrivere il proprio analizzatore che tokenizza vostri nomi chimici il modo in cui avete bisogno per i vostri casi d'uso.

Avanti il ??parser query. Assicurati di conoscere la sintassi di query - Lucene interrogazione sintassi . Alcuni caratteri hanno un significato speciale, per esempio, un '-'. Potrebbe essere che la query viene analizzato il modo sbagliato.

In entrambi i casi, os primo gradino per scoprire come i vostri nomi chimici vengono token. Speranza che aiuta.

Altri suggerimenti

Usa WhitespaceAnalyzer invece di StandardAnalyzer. E 'solo dividere a spazi bianchi, e non a virgole, trattini, ecc (Non sarà minuscolo loro però, quindi sarà necessario per costruire la propria catena di spazi bianchi + minuscolo, supponendo che si desidera la vostra ricerca per essere case-insensitive). Se avete bisogno di fare le cose in modo diverso per i diversi campi, è possibile utilizzare un PerFieldAnalyzer.

È possibile non solo impostare per non-token, perché che interpretare il vostro intero corpo del testo come un token.

Ho scritto il mio analizzatore:

import java.util.Set;
import java.util.regex.Pattern;

import org.apache.lucene.index.memory.PatternAnalyzer;
import org.apache.lucene.util.Version;

public class ChemicalNameAnalyzer extends PatternAnalyzer {

    private static Version version = Version.LUCENE_29;
    private static Pattern pattern = compilePattern();
    private static boolean toLowerCase = true;
    private static Set stopWords = null;

    public ChemicalNameAnalyzer(){
        super(version, pattern, toLowerCase, stopWords);
    }

    public static Pattern compilePattern() {
        StringBuilder sb =  new StringBuilder();
        sb.append("(-{0,1}\\(-{0,1})");//Matches an optional dash followed by an opening round bracket followed by an optional dash  
        sb.append("|");//"OR" (regex alternation)
        sb.append("(-{0,1}\\)-{0,1})"); 
        sb.append("|");//"OR" (regex alternation)
        sb.append("((?<=([a-zA-Z]{2,}))-(?=([^a-zA-Z])))");//Matches a dash ("-") preceded by two or more letters and succeeded by a non-letter
        return Pattern.compile(sb.toString());
    }
}
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top