Configure Sphinx Search para una tienda en línea

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 

Source: https://habr.com/ru/post/439018/


All Articles