tutorial example java search lucene

java - example - Lucene: frases de varias palabras como términos de búsqueda



lucene vs elasticsearch (4)

Estoy tratando de crear un directorio de teléfono / local de búsqueda con Apache Lucene.

Tengo campos para el nombre de la calle, el nombre de la empresa, el número de teléfono, etc. El problema que tengo es que cuando trato de buscar por la calle donde el nombre de la calle tiene varias palabras (por ejemplo, ''la media luna''), no se devuelven resultados. Pero si trato de buscar con solo una palabra, por ejemplo, ''creciente'', obtengo todos los resultados que deseo.

Estoy indexando los datos con lo siguiente:

String LocationOfDirectory = "C://dir//index"; StandardAnalyzer analyzer = new StandardAnalyzer(Version.LUCENE_34); Directory Index = new SimpleFSDirectory(LocationOfDirectory); IndexWriterConfig config = new IndexWriterConfig(Version.LUCENE.34, analyzer); IndexWriter w = new IndexWriter(index, config); Document doc = new Document(); doc.add(new Field("Street", "the crescent", Field.Store.YES, Field.Index.Analyzed); w.add(doc); w.close();

Mis búsquedas funcionan así:

int numberOfHits = 200; String LocationOfDirectory = "C://dir//index"; TopScoreDocCollector collector = TopScoreDocCollector.create(numberOfHits, true); Directory directory = new SimpleFSDirectory(new File(LocationOfDirectory)); IndexSearcher searcher = new IndexSearcher(IndexReader.open(directory); WildcardQuery q = new WildcardQuery(new Term("Street", "the crescent"); searcher.search(q, collector); ScoreDoc[] hits = collector.topDocs().scoreDocs;

He intentado intercambiar la consulta de comodín para una consulta de frase, primero con la cadena completa y luego dividir la cadena en un espacio en blanco y envolverlos en una BooleanQuery como esta:

String term = "the crescent"; BooleanQuery b = new BooleanQuery(); PhraseQuery p = new PhraseQuery(); String[] tokens = term.split(" "); for(int i = 0 ; i < tokens.length ; ++i) { p.add(new Term("Street", tokens[i])); } b.add(p, BooleanClause.Occur.MUST);

Sin embargo, esto no funcionó. Intenté usar un KeywordAnalyzer en lugar de un StandardAnalyzer, pero luego todos los otros tipos de búsqueda dejaron de funcionar también. He intentado reemplazar espacios con otros caracteres (+ y @) y convertir consultas de este formulario, pero todavía no funciona. Creo que no funciona porque + y @ son caracteres especiales que no están indexados, pero parece que no puedo encontrar una lista en la que los personajes sean así.

Estoy empezando a enojarme un poco, ¿alguien sabe lo que estoy haciendo mal?

Gracias, Rik


La razón por la que no recupera sus documentos es que, al indexar, usa StandardAnalyzer , que convierte los tokens a minúsculas y elimina las palabras de último minuto. Entonces, el único término que se indexa para su ejemplo es ''creciente''. Sin embargo, las consultas con comodines no se analizan, por lo que ''el'' se incluye como parte obligatoria de la consulta. Lo mismo ocurre con las consultas de frase en su escenario.

KeywordAnalyzer probablemente no sea muy adecuado para su caso de uso, ya que toma todo el contenido del campo como un único token. Puede usar SimpleAnalyzer para el campo calle - dividirá la entrada en todos los caracteres que no sean letras y luego los convertirá a minúsculas. También puede considerar usar WhitespaceAnalyzer con LowerCaseFilter . Debe probar diferentes opciones y determinar qué funciona mejor para sus datos y usuarios.

Además, puede usar diferentes analizadores por campo (por ejemplo, con PerFieldAnalyzerWrapper ) si el cambio de analizador para ese campo interrumpe otras búsquedas.


Descubrí que mi intento de generar una consulta sin utilizar un QueryParser no funcionaba, por lo que dejé de intentar crear mis propias consultas y usé un QueryParser en su lugar. Todas las recomendaciones que vi en línea mostraron que debe usar el mismo Analizador en QueryParser que usa durante la indexación, entonces usé un StandardAnalyzer para construir QueryParser.

Esto funciona en este ejemplo porque el StandardAnalyzer elimina la palabra "the" de la calle "the crescent" durante la indexación, y por lo tanto no podemos buscarla porque no está en el índice.

Sin embargo, si elegimos buscar "Grove Road", tenemos un problema con la funcionalidad lista para usar, es decir, que la consulta devolverá todos los resultados que contengan "Grove" O "Road". Esto se soluciona fácilmente configurando QueryParser para que su operación predeterminada sea AND en lugar de OR.

Al final, la solución correcta fue la siguiente:

int numberOfHits = 200; String LocationOfDirectory = "C://dir//index"; TopScoreDocCollector collector = TopScoreDocCollector.create(numberOfHits, true); Directory directory = new SimpleFSDirectory(new File(LocationOfDirectory)); IndexSearcher searcher = new IndexSearcher(IndexReader.open(directory); StandardAnalyzer analyzer = new StandardAnalyzer(Version.LUCENE_35); //WildcardQuery q = new WildcardQuery(new Term("Street", "the crescent"); QueryParser qp = new QueryParser(Version.LUCENE_35, "Street", analyzer); qp.setDefaultOperator(QueryParser.Operator.AND); Query q = qp.parse("grove road"); searcher.search(q, collector); ScoreDoc[] hits = collector.topDocs().scoreDocs;


Si quiere que las palabras exactas coincidan con la calle, puede establecer el campo "Calle" NOT_ANALYZED que no filtrará la palabra de detención "the".

doc.add(new Field("Street", "the crescent", Field.Store.YES, Field.Index.Not_Analyzed);


No es necesario utilizar ningún Analyzer aquí porque Hibernate utiliza implícitamente StandardAnalyzer que dividirá las palabras basadas en white spaces en white spaces por lo que la solución aquí se establece Analyze en NO , automáticamente realizará la Multi Phrase Search

@Column(name="skill") @Field(index=Index.YES, analyze=Analyze.NO, store=Store.NO) @Analyzer(definition="SkillsAnalyzer") private String skill;