2010-04-13 15 views
10

En la sintaxis de consulta de Lucene me gustaría combinar * ~ y en una consulta válida similar a: bla ~ * // consulta no válidaPregunta de Lucene: bla ~ * (coincide con palabras que comienzan con algo borroso), ¿cómo?

Significado: Por favor, que coincida con las palabras que comienzan con "bla" o algo similar a "bla".

actualización: Lo que hago ahora, trabaja para pequeñas de entrada, es utilizar la siguiente (fragmento de esquema SOLR):

<fieldtype name="text_ngrams" class="solr.TextField"> 
    <analyzer type="index"> 
     <tokenizer class="solr.WhitespaceTokenizerFactory"/> 
     <filter class="solr.WordDelimiterFilterFactory" generateWordParts="1" generateNumberParts="1" catenateWords="1" catenateNumbers="1" catenateAll="0" splitOnCaseChange="0"/> 
     <filter class="solr.LowerCaseFilterFactory"/> 
     <filter class="solr.EdgeNGramFilterFactory" minGramSize="2" maxGramSize="15" side="front"/> 
    </analyzer> 
    <analyzer type="query"> 
     <tokenizer class="solr.WhitespaceTokenizerFactory"/> 
     <filter class="solr.WordDelimiterFilterFactory" generateWordParts="1" generateNumberParts="1" catenateWords="0" catenateNumbers="0" catenateAll="0" splitOnCaseChange="0"/> 
     <filter class="solr.LowerCaseFilterFactory"/> 
    </analyzer> 

En caso de que no utilizan SOLR, esto hace lo siguiente.

Indextime: Indique los datos creando un campo que contenga todos los prefijos de mi entrada (corta).

Tiempo de búsqueda: solo use el ~ operador, ya que los prefijos están explícitamente presentes en el índice.

Respuesta

2

No creo que Lucene soporte algo como esto, ni creo que tenga una solución trivial.

Las búsquedas "borrosas" no funcionan en un número fijo de caracteres. bla~ puede, por ejemplo, coincidir con blah, por lo que debe considerar todo el término.

Lo que podría hacer es aplicar un algoritmo de ampliación de la consulta que se llevó a la consulta bla~* y lo convirtió en una serie de consultas o

bla* OR blb* OR blc OR .... etc. 

Pero esto es realmente sólo es viable si la cadena es muy corta o si puede reducir la expansión en función de algunas reglas.

De forma alternativa, si se fija la longitud del prefijo, podría agregar un campo con las subcadenas y realizar la búsqueda difusa sobre eso. Eso le daría lo que quiere, pero solo funcionará si su caso de uso es suficientemente estrecho.

No especifica exactamente por qué necesita esto, quizás hacerlo provocará otras soluciones.

Un caso en el que puedo pensar es que se trata de una forma diferente de palabras. P.ej. encontrando car y cars.

Esto es fácil en inglés, ya que hay word stemmers disponibles. En otros idiomas, puede ser bastante difícil implementar stemmers de palabras, si no imposible.

En este caso, puede (suponiendo que tenga acceso a un buen diccionario) buscar el término de búsqueda y expandir la búsqueda programáticamente para buscar todas las formas de la palabra.

E.g. una búsqueda de cars se traduce al car OR cars. Esto se ha aplicado con éxito para mi idioma en al menos un motor de búsqueda, pero obviamente no es trivial de implementar.

+0

Althoug búsquedas difusas no operan en un número fijo de caracteres, para mi caso simplemente usando ~ no funcionará (a gran diff en el recuento de caracteres). Quiero hacer coincidir, p. Sunla a Sundlaugarvegur. –

+0

por supuesto, si pudiera decirle a lucene que solo coincida con los primeros x caracteres de cada palabra en el índice, usar ~ funcionaría ... –

+0

Tendría que ir más allá de Lucene aquí, usar un algoritmo de comparación de cadenas como Levenstein, Jaro -Winkler, etc. (qv abajo) – Mikos

0

¿Quiere decir que desea combinar un comodín y una consulta difusa?Se podría utilizar una consulta booleana con una condición OR para combinar, por ejemplo:

BooleanQuery bq = new BooleanQuery(); 

Query q1 = //here goes your wildcard query 
bq.Add(q1, BooleanClause...) 

Query q2 = //here goes your fuzzy query 
bq.Add(q2, BooleanClause...) 
+0

No creo que esto logre lo que el OP está pidiendo, ya que básicamente se convertiría en "bar ~ O barra *" que no es lo mismo que "bar ~ *" y no encontraría (por ejemplo) "brafoo". – Kris

+0

sí, esto no es lo que quiero :) –

+0

Ok, gracias por aclarar, un enfoque que he usado (para encontrar los nombres de las proteínas, etc.) usando distancias de cuerdas como Smith-Waterman, Jaro-Winkler, etc. Una herramienta como SimMetrics podría ser de alguna ayuda http://www.dcs.shef.ac.uk/~sam/simmetrics.html – Mikos

1

Es para un servicio de búsqueda de direcciones, donde quiero sugerir direcciones basado en parte mecanografiado y posiblemente mal escritas nombres de calles/citynames/etc (cualquier combinación). (Piensan ajax, los usuarios al escribir direcciones de calles parciales en un campo de texto)

Para este caso, la expansión de consultas sugerido tal vez no sea tan factible, ya que la cadena parcial (dirección de la calle) pueden llegar a ser más largo que "corta" :)

normalización

Una posibilidad que se me ocurre es el uso de cadena "normalización", en lugar de búsquedas difusas, y simplemente combinar eso con comodines en una consulta. Una dirección postal de

"miklabraut 42, 101 reykjavík", se convertiría en "miklabrat 42 101 rekavik" cuando se normaliza.

Así, el índice de edificio como este:

1) realizar un índice con los registros que contienen las versiones "normalizados" de nombres de calles, nombres de ciudades, etc., con una dirección de la calle por documento (1 o varios campos).

y buscar en el índice como este:

2) Normalizar inputstrings (por ejemplo mikl reyk) usado para formar las consultas (es decir mik rek). 3) use el comodín op para realizar la búsqueda (es decir, mik* AND rek*), dejando la parte difusa.

que volaría, siempre que el algoritmo de normalización es lo suficientemente bueno :)

7

en el maletero desarrollo de Lucene (todavía sin una nueva versión), no hay código para apoyar a los casos de uso de este tipo, a través de AutomatonQuery. Advertencia: las API pueden/cambiarán antes de su lanzamiento, pero te da la idea.

Aquí es un ejemplo para su caso:

// a term representative of the query, containing the field. 
// the term text is not so important and only used for toString() and such 
Term term = new Term("yourfield", "bla~*"); 

// builds a DFA that accepts all strings within an edit distance of 2 from "bla" 
Automaton fuzzy = new LevenshteinAutomata("bla").toAutomaton(2); 

// concatenate this DFA with another DFA equivalent to the "*" operator 
Automaton fuzzyPrefix = BasicOperations.concatenate(fuzzy, BasicAutomata.makeAnyString()); 

// build a query, search with it to get results. 
AutomatonQuery query = new AutomatonQuery(term, fuzzyPrefix); 
+0

Acabo de volver a esta pregunta y volví a ver tu respuesta. ¿Lo has probado? Lo que estoy haciendo ahora (funciona para pequeñas entradas), es generar todos los prefijos de mi entrada y poner los prefijos en el índice.Entonces sólo tengo que utilizar el operador ~, y obtener la funcionalidad como ~ * –

+0

Su solución es bien para entradas pequeñas ... pero como se insinuó, a ser un problema para las grandes aportaciones: se le agrega una gran cantidad de términos y publicaciones para todos estos prefijos ... esto hará que la consulta difusa pre-Lucene 4.0 sea aún más lenta ya que realiza un escaneo lineal de todos los términos. –

+0

¿Existe una sintaxis de consulta Lucene que le da acceso a la consulta de Automaton a través de Solr sin codificación? – wrschneider

Cuestiones relacionadas