2012-06-04 12 views
9

Estoy probando el rendimiento para la búsqueda de texto completo de PostgreSQL (usando la gema pg_search) y la solr (gema sunspot_solr).Índice de texto completo correcto Rails/PostgreSQL/pg_search

Para 4 millones de discos que estoy recibiendo 13456 ms para Tsearch y 800 ms con SOLR (es decir SOLR consulta + retrival DB). Es obvio que necesito un índice, pero no estoy seguro de cómo crear uno para la búsqueda de texto completo. Investigué y encontré que para la búsqueda de texto completo debería usar el índice GIN.

execute "CREATE INDEX products_gin_title ON products USING GIN(to_tsvector('english', title))" 

Pero Estoy buscando a través de dos columnas más y necesito índice de valores múltiples y no estoy seguro de cómo ponerlo en práctica? No estoy muy familiarizado con la parte de DB. Mi código de búsqueda se ve así:

@results = Product.search_title(params[:search_term]).where("platform_id=? AND product_type=?", params[:platform_id], params[:type_id]).limit(10).all 

¿Cómo se crea la consulta apropiada para este tipo de situaciones?

Aquí está la salida SQL de los rieles para el término de búsqueda auto.

Product Load (12494.0ms) 
SELECT 
    "products".*, 
    (ts_rank((to_tsvector('simple', coalesce("products"."title"::text, ''))), (to_ tsquery('simple', ''' ' || 'car' || ' ''')), 2)) AS pg_search_rank 
FROM "products" 
WHERE (((to_tsvector('simple', coalesce("products"."tit le"::text, ''))) @@ (to_tsquery('simple', ''' ' || 'car' || ' ''')))) 
    AND (platform_id='26' AND product_type='2') 
ORDER BY pg_search_rank DESC, "products"."id" ASC 
LIMIT 10 

EDIT:

estoy usando PostgreSQL 8.4.11, EXPLAIN ANALYZE salida está siguiendo.

Limit (cost=108126.34..108126.36 rows=10 width=3824) (actual time=12228.736..12228.738 rows=10 loops=1) 
-> Sort (cost=108126.34..108163.84 rows=14999 width=3824) (actual time=12228.733..12228.734 rows=10 loops=1) 
    Sort Key: (ts_rank(to_tsvector('simple'::regconfig, COALESCE((title)::text, ''::text)), '''car'''::tsquery, 2)), id 
    Sort Method: top-N heapsort Memory: 18kB 
    -> Seq Scan on products (cost=0.00..107802.22 rows=14999 width=3824) (actual time=7.532..12224.585 rows=977 loops=1) 
     Filter: ((platform_id = 26) AND (product_type = 2) AND (to_tsvector('simple'::regconfig, COALESCE((title)::text, ''::text)) @@ '''car'''::tsquery)) 

Total runtime: 12228.813 ms 
+0

Por favor, publique el resultado de ejecutar 'EXPLAIN ANALYZE' en la consulta publicada, más su versión Pg, cualquier parámetro postgresql.conf que haya cambiado, etc. –

Respuesta

8

Esta expresión:

to_tsvector('simple', (COALESCE(title::TEXT), '')) 

no es sargable en contra de su índice.

Usted debe declarar el índice en el que exactamente la expresión que se utiliza en la consulta:

CREATE INDEX products_gin_title 
ON products 
USING GIN(to_tsvector('simple', COALESCE(title::TEXT,''))) 

(o hacer rubí generar la expresión que se utiliza en el índice).

Si desea varias columnas para ser indexados, simplemente concatenar:

CREATE INDEX products_gin_title 
ON products 
USING GIN(to_tsvector('simple', title || ' ' || product_type || ' ' || platform_id)) 

pero de nuevo, Ruby debe ser filtrado en exactamente la misma expresión para que el índice sea de uso.

+0

Gracias primer índice de una sola columna trabajada ahora el tiempo de consulta es 80 ms, ¡bonito! Pregunta para usted, además de esto, ¿debería ser un índice de varias columnas para aumentar aún más la velocidad? Cuando dices concatenarlos, ¿significa eso que debo hacer una búsqueda de texto completo concatenando los ID de FK con mi término de búsqueda? –

+0

@Dolphin: ¿qué 'FK ids'? – Quassnoi

+0

En este ejemplo, estoy buscando el título a través del texto completo, y también estoy reduciendo los resultados con product_type, platform_id (FK mencionados). Tengo la impresión de que si desea acelerar una consulta específica, debe agregar el índice para TODAS las columnas utilizadas en esa consulta. –

Cuestiones relacionadas