En el sitio de comercio electrónico para el que trabajo, utilizamos Solr para proporcionar una rápida facetación y búsqueda en el catálogo de productos. (En términos que no son de Solr geek, esto significa el estilo de enlaces de navegación "ATI Cards (34), NVIDIA (23), Intel (5)" que puede usar para profundizar en catálogos de productos en sitios como Zappos, Amazon, NewEgg y Lowe's)
Esto es porque Solr está diseñado para hacer este tipo de cosas rápido y bien, y tratar de hacer este tipo de cosas de manera eficiente en una base de datos relacional tradicional no va a suceder, a menos que desea comenzar a agregar y eliminar índices sobre la marcha e ir completo EAV, que es sólo tos Magento tos estúpido. Por lo tanto, nuestra base de datos de SQL Server es el almacén de datos "autorizado", y los índices de Solr son "proyecciones" de solo lectura de esos datos.
Estás conmigo hasta ahora porque parece que estás en una situación similar. El siguiente paso es determinar si está bien o no que los datos en el índice de Solr estén un poco obsoletos. Probablemente haya aceptado el hecho de que será un tanto obsoleto, pero las siguientes decisiones son
- ¿Qué tan añejo está demasiado rancio?
- ¿Cuándo valoro la velocidad o las características de consulta sobre la estanqueidad?
Por ejemplo, tengo lo que llamo el "trabajador", que es un servicio de Windows que utiliza para ejecutar Quartz.NET C# IJob
implementaciones periódicamente. Cada 3 horas, uno de estos trabajos que se ejecuta es el RefreshSolrIndexesJob
, y todo lo que hace es enviar un ping a HttpWebRequest
a http://solr.example.com/dataimport?command=full-import
. Esto se debe a que utilizamos el DataImportHandler incorporado de Solr para realmente absorber los datos de la base de datos SQL; el trabajo solo tiene que "tocar" esa URL periódicamente para que la sincronización funcione. Debido a que DataImportHandler confirma los cambios periódicamente, esto se está ejecutando efectivamente en segundo plano, de forma transparente para los usuarios del sitio web.
Esto significa que la información en el catálogo de productos puede durar hasta 3 horas. Un usuario puede hacer clic en un enlace para "Medio en Stock (3)" en la página del catálogo (ya que este tipo de datos facetados se genera consultando SOLR) pero luego ver en la página de detalles del producto que no hay medios almacenados (ya que página, la información de cantidad es una de las pocas cosas no en caché y consulta directamente en la base de datos). Esto es molesto, pero generalmente raro en nuestro escenario particular (somos un negocio razonablemente pequeño y no que alto tráfico), y se arreglará en 3 horas de todos modos cuando reconstruyamos todo el índice nuevamente desde cero, entonces tenemos aceptado esto como una compensación razonable.
Si puede aceptar este grado de "estancamiento", entonces este proceso de trabajo en segundo plano es una buena forma de hacerlo. Podría tomar el enfoque de "reconstruir todo en pocas horas", o su repositorio podría insertar el ID en una tabla, por ejemplo, dbo.IdentitiesOfStuffThatNeedsUpdatingInSolr
, y luego un proceso en segundo plano puede escanear periódicamente esa tabla y actualizar solo esos documentos en Solr si se reconstruye el índice completo desde cero periódicamente no es razonable dado el tamaño o la complejidad de su conjunto de datos.
Un tercer enfoque es tener su repositorio generará un subproceso de fondo que actualiza el índice de Solr en cuanto a que el documento actual, más o menos al mismo tiempo, por lo que los datos sólo está viciado por unos segundos:
class MyRepository
{
void Save(Post post)
{
// the following method runs on the current thread
SaveThePostInTheSqlDatabaseSynchronously(post);
// the following method spawns a new thread, task,
// queueuserworkitem, whatevever floats our boat this week,
// and so returns immediately
UpdateTheDocumentInTheSolrIndexAsynchronously(post);
}
}
Pero si esto explota por alguna razón, puede perder actualizaciones en Solr, por lo que es una buena idea hacer que Solr haga un "soplarlo todo y actualizarlo" periódicamente, o tener un reaper de fondo. Servicio de tipo trabajador que verifica para datos desactualizados en Solr, todos una vez en una luna azul.
En cuanto a consultar estos datos de Solr, hay algunos enfoques que puede tomar. Una es ocultar el hecho de que Solr existe completamente a través de los métodos del Depósito. Personalmente, no lo recomiendo porque es probable que su esquema de Solr se adapte descaradamente a la interfaz de usuario que accederá a esos datos; Ya tomamos la decisión de usar Solr para proporcionar una fácil facetación, clasificación y visualización rápida de la información, por lo que también podríamos utilizarla en toda su extensión. Esto significa hacerlo explícito en el código cuando queremos acceder a Solr y cuando queremos acceder al objeto de base de datos actualizado, no en caché.
En mi caso, termino utilizando NHibernate para hacer el acceso CRUD (cargando un ItemGroup
, continuando con sus reglas de fijación de precios, y luego guardándolo de nuevo), renunciando al patrón de repositorio porque normalmente no veo su valor cuando NHibernate y sus asignaciones ya están abstrayendo la base de datos. (Esta es una elección personal.)
Pero al consultar en los datos, lo sé muy bien si lo estoy usando con fines orientados Catálogo-(me importa velocidad y consultar ) o para la visualización en una tabla en una aplicación administrativa back-end (me importa moneda). Para consultar en el sitio web, tengo una interfaz llamada ICatalogSearchQuery
. Tiene un método Search()
que acepta un SearchRequest
donde defino algunos parámetros - facetas seleccionadas, términos de búsqueda, número de página, número de elementos por página, etc. - y devuelve un SearchResult
- facetas restantes, número de resultados, resultados en esta página, etc. Bastante aburrido.
Donde se pone interesante es que la implementación de ese ICatalogSearchQuery
está usando una lista de ICatalogSearchStrategy
s debajo. La estrategia predeterminada, SolrCatalogSearchStrategy
, accede directamente a SOLR a través de un simple HttpWebRequest
y analizando el XML en HttpWebResponse
(que es mucho más fácil de usar, en mi humilde opinión, que algunas de las bibliotecas de SOLR, aunque pueden haber mejorado desde que La última vez que los miré hace más de un año). Si esa estrategia arroja una excepción o vomita por alguna razón, entonces el DatabaseCatalogSearchStrategy
golpea directamente la base de datos SQL, aunque ignora algunos parámetros del SearchRequest
, como la creación de facetas o la búsqueda de texto avanzada, ya que es ineficiente hacerlo allí y es la razón principal estamos usando Solr en primer lugar. La idea es que, por lo general, SOLR está respondiendo mis solicitudes de búsqueda rápidamente con todas las funciones, pero si algo explota y SOLR falla, las páginas del catálogo del sitio todavía pueden funcionar en el "modo de funcionalidad reducida" accediendo a la base de datos con un conjunto limitado de características directamente. (Ya que hemos explicitado en el código que se trata de una búsqueda, esta estrategia puede tomar algunas libertades en ignorar algunos de los parámetros de búsqueda sin tener que preocuparse por que afecta a los clientes con demasiada severidad.)
conclusión clave: Lo que es importante es que la decisión de realizar una consulta contra un almacén de datos posiblemente obsoleto versus el almacén de datos autoritativo se ha realizado explicita --si quiero datos rápidos, posiblemente obsoletos con funciones de búsqueda avanzada, uso ICatalogSearchQuery
.Si quiero datos lentos y actualizados con la capacidad de insertar/actualizar/eliminar, utilizo las consultas nombradas de NHibernate (o un repositorio en su caso). Y si realizo un cambio en la base de datos de SQL, sé que el servicio de trabajo fuera de proceso actualizará Solr eventualmente, haciendo que las cosas finalmente sean consistentes. (Y si algo era realmente importante, podía transmitir un evento o hacer ping a la tienda SOLR directamente, pidiéndole que lo actualizara, posiblemente en un hilo de fondo si era necesario).
Espero que te dé una idea.
¡excelente respuesta! Utilizo la indexación de Solr de forma ligeramente diferente en el sentido de que la configuración de Solr está configurada para consultar por lotes nuevos registros en un período determinado. De esta forma, no fue necesario escribir ningún código, solo un cambio en la configuración de Solr. Una vez que Solr devuelve coincidencias de búsqueda, actualmente cargo todos los datos para cada partido de NHibernate, aunque pretendo cambiar esto para tener todos los datos de visualización requeridos devueltos por Solr como un punto. Nunca he conseguido que funcione la importación por lotes, pero necesito hacerlo pronto en caso de que el índice corrompa o modifique los campos indexados. – Jordan