No hay tanta información sobre Sphinx como nos gustaría. El exceso de artículo no duele.
Los primeros pasos en el desarrollo de Sphinx me ayudaron a hacer los artículos Creación de un motor de búsqueda introductorio en Sphinx + php y Sphinx Ejemplo de búsqueda en un proyecto real - Tecdoc auto parts store Le aconsejo que comience con ellos.
Durante algún tiempo, una búsqueda en LIKE para cada palabra de la consulta funcionó en mi sitio. Quería más, y aquí hay algunos casos que ahora se manejarán correctamente:
- Formas de palabras La salida para "tornillos" y "tornillos" debe ser la misma.
- Búsqueda por fragmento de palabra.
- Busca números no enteros. Separador de punto y coma.
- Letra y
- Errores comunes Por ejemplo, "Amortiguador".
- Sinónimos Regulador y ESC.
- Idioma. mAh y mAh, B y V, AAA latino y cirílico.
- Palabra compuesta de letras y números. 10x15x4, 6000mAh
Sección fuente y clasificación opcional
El problema primero debe contener artículos en stock, luego temporalmente ausentes, luego archivados. Y los tres grupos deben ordenarse por relevancia. Para hacer esto, debe establecer los atributos. En mi caso, estos son los campos de despeje e in_stock de la sección fuente sphinx.conf
sql_query = \ SELECT id, `art`, `name`, `clearance`, `in_stock` \ FROM items_zip WHERE show_flag=1 sql_attr_bool = clearance sql_attr_uint = in_stock
Estos campos se utilizarán para generar resultados en PHP. Lo describiré a continuación.
Sección de índice en sphinx.conf
morfología = stem_enru
La morfología resuelve mi primer problema. Una búsqueda de 'rodamientos', 'rodamientos', 'rodamientos' conducirá a un único resultado.
Los tallos (stem_enru) son más rápidos, los lemmas (lemmatize_ru) son más precisos. Intenté solo con tartamudeos. La elección afectará su diccionario de reemplazos de formas de palabras. Quiere cambiar, tiene que reescribir.
min_word_len = 1
Palabras de índice de cualquier longitud.
html_strip = 1
Eliminar etiquetas html
min_infix_len = 1
La búsqueda estará en un fragmento de la palabra. Índice de fragmentos de hasta 1 letra. Como tengo menos de 10.000 elementos en la base de datos, no guardo en el índice.
expand_keywords = 1
Lleva automáticamente la consulta al formulario "(en ejecución | en ejecución | = en ejecución)". min_infix_len y expand_keywords harán que RV 2205 emita RV2205. Por cierto, un guión es un separador equivalente a un espacio. Entonces el RV-2205 dará el mismo RV2205.
charset_table = 0..9, A..Z-> a..z, _, a..z, U + 410..U + 42F-> U + 430..U + 44F, U + 430..U + 44F, U + 401-> U + 0435, U + 451-> U + 0435
Traemos el alfabeto latino y el alfabeto cirílico en minúsculas. reemplazar con e.
blend_chars = +, &, U + 2C, U + 2E
Tengo muchos números no enteros. Necesitan estar completamente indexados. U + 2C y U + 2E son un punto y una coma. Por ejemplo, 1.25 se indexará como '1.25', '1' y '25'.
regexp_filter = (\ d +) \, (\ d +) => \ 1. \ 2
Los lugares decimales en los números se pueden separar por puntos y comas: "1.75", "1.75". Llevamos todo al punto
Sinónimos y errores tipográficos
Las unidades de medida pueden escribirse en ruso o inglés: mm-mm, mAh-mAh, mW-mW. Agregue al diccionario de sinónimos, la ruta a la que se especifica en las formas de palabras: "mach> mah". Elijo el idioma para el índice de acuerdo con mis propias preferencias.
El signo ~ indica que se debe aplicar el reemplazo después del controlador de morfología. Esto le permite no escribir todas las formas de palabras y en lugar de las reglas para 'corteza', 'corteza', 'corteza' escriba "~ corcho> cuerpo"
Mi lista esta completa:
~ > esc > esc > mah ~ > ~ > ~ > buzz ~ > buzz ~ > buzz ~ > buzz ~ > buzz ~ > ~ > ~ > li-po > lipo ~ > ~ > > > vtx > ~ > lollipop > lolipop battery > ~ > ~ > ~ > mkF > > BEC > BEC ~ > LED > ~ > driver > ~ > ~ > > AAA > AA > M mm > > mW > V > A deans > t-plug tplug > t-plug
Pegar letras a números
A veces, los números son parte del nombre (por ejemplo, LCD5208D), pero con mayor frecuencia son una característica (100 mAh, 10x15x4 mm). Separe todos los números de las letras y el índice.
Esto resolverá varios problemas:
- Alguien estará buscando 'teniendo 10x15x4', alguien 'teniendo 15x10x4'. Los números indexados darán como resultado la salida correcta.
- Las unidades de medida pueden o no estar separadas por un espacio del número: "1.75 mm", "1.75 mm".
- Para los títulos, esto también es útil. La salida correcta estará en las tres opciones de grabación LCD-5208, LCD 5208 y LCD5208
Antes de escribir una expresión regular para separar números, debe unificar los delimitadores. Es importante recordar que las expresiones regulares se ejecutan todas y secuencialmente.
Eliminamos la x, él y la estrella en tamaños como 10x4x4 M3x10:
regexp_filter = (\d+)[x\x{0445}\*] => \1 x
Suelta las colas:
regexp_filter = (\d*\.?\d+)(\D+) => \1 \2
Y las cabezas:
regexp_filter = (\D+)(\d*\.?\d+) => \1 \2
Desechamos "mm", ya que a menudo no se indican en el nombre del producto.
Haga un archivo stop.txt y escríbalo en palabras vacías.
Contenido:
mm
Ahora un poco sobre PHP
Sphinxapi será depricate tarde o temprano. Utilizaremos Sphinxql. Para hacer esto, conéctese a la base de datos. En mi caso, Sphinx está conectado a través de hosting, se ve así:
$opt = array( PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, PDO::ATTR_EMULATE_PREPARES => TRUE, ); $dsn = 'mysql:host=127.0.0.1;port=9306;'; $this->pdo = new PDO($dsn, DB_USER, DB_PASS, $opt);
Y toda comunicación con Spinxql es un texto de consulta filtrado de transmisión SELECT
$stmt = $this->pdo->prepare("SELECT `id`, WEIGHT() as `w`, in_stock>0 AS stock FROM `items` WHERE MATCH ('".$search."') ORDER BY clearance ASC, stock DESC, w DESC LIMIT ".$limit." OPTION field_weights=(name=10, art=3, cat_names=3, model_names=3)");
SphinxQL no comprende las expresiones en la sección de ordenación ORDER BY, por lo que WEIGHT () y in_stock> 0 tuvieron que colocarse en campos. Por cierto, el límite predeterminado es solo 20.
La clasificación producirá primero artículos en stock, luego temporalmente ausentes, luego archivados. Y todos estos tres grupos se ordenarán por relevancia (peso).
A través de field_weights establecemos qué campos tendrán más peso.
Al completar la solicitud, obtenemos una matriz de identificación ordenada. Pero, desafortunadamente, la selección de datos a través de WHERE id IN () violará esta clasificación. Tiene que formar su solicitud para cada identificación.
En la fase de depuración , la consulta SHOW META inmediatamente después de la consulta SELECT ayuda mucho. Especialmente para verificar formas de palabras del diccionario y filtros de expresiones regulares. Puede ver la lista de palabras clave en las que se ha expandido la consulta.
Complicando sql_query
Vendemos repuestos. Decidí agregar el nombre de la categoría de producto y el nombre del modelo para el cual se pretende agregar la pieza de repuesto al índice. Pero cada producto puede vincularse a varias categorías a la vez y ser adecuado para varios modelos. Y descubrí la función GROUP_CONCAT , que le permite obtener datos al agruparlos en una cadena. Por ejemplo, el campo categories.name contendrá todas las categorías de items_zip.id seleccionados separadas por espacios.
SELECT items_zip.id, `art`, items_zip.`name`, `clearance`, `in_stock`, GROUP_CONCAT(DISTINCT categories.name SEPARATOR ' ') AS cat_names, GROUP_CONCAT(DISTINCT items.family SEPARATOR ' ') AS model_names FROM items_zip LEFT JOIN items_cat ON items_cat.item_id=items_zip.id LEFT JOIN categories ON categories.id=items_cat.cat_id LEFT JOIN zip_comp ON zip_comp.zip_id=items_zip.id LEFT JOIN items ON zip_comp.model_id=items.id WHERE items_zip.show_flag=1 GROUP BY items_zip.id