Implemente Lucene en la pila de.NET/SQL Server existente con varios servidores web
sql-server lucene.net (1)
Quiero ver cómo usar Lucene para una solución de búsqueda de texto completo para un sitio que administro actualmente. El sitio está construido completamente en tecnologías SQL Server 2008 / C # .NET 4. Los datos que busco indexar son en realidad bastante simples, con solo un par de campos por registro y solo uno de esos campos se puede buscar.
No me queda claro cuál es el mejor conjunto de herramientas que necesito usar o la arquitectura que debería usar. Específicamente:
¿Dónde debo poner el índice? He visto a gente recomendar ponerlo en el servidor web, pero eso parecería un desperdicio para un gran número de servidores web. ¿Seguramente sería mejor centralizar aquí?
Si el índice está centralizado, ¿cómo lo consultaría, dado que solo vive en el sistema de archivos? ¿Tendré que ponerlo de manera efectiva en un recurso compartido de red que todos los servidores web puedan ver?
¿Existen herramientas preexistentes que poblarán de forma incremental un índice de Lucene en un horario, extrayendo los datos de una base de datos de SQL Server? ¿Sería mejor rodar mi propio servicio aquí?
Cuando pregunto por el índice, ¿debería buscar simplemente retroceder un grupo de ID de registro que luego vuelvo a la base de datos para el registro real, o debería apuntar a sacar todo lo que necesito para la búsqueda directamente del índice? ?
¿Hay valor en tratar de implementar algo como Solr en este entorno de sabor? Si es así, probablemente le daría su propia * nix VM y la ejecutaría dentro de Tomcat. Pero no estoy seguro de lo que Solr me compraría en este caso.
Responderé un poco en función de cómo decidimos implementar Lucene.Net aquí en , y algunas lecciones que aprendí en el camino:
¿Dónde debo poner el índice? He visto a gente recomendar ponerlo en el servidor web, pero eso parecería un desperdicio para un gran número de servidores web. ¿Seguramente sería mejor centralizar aquí?
- Depende de sus objetivos aquí, tuvimos un nivel web muy infrautilizado (~ 10% de CPU) y una base de datos sobrecargada que realiza búsquedas de texto completo (alrededor del 60% de CPU, lo queríamos más bajo). Al cargar el mismo índice en cada nivel web, podemos utilizar esas máquinas y tener una tonelada de redundancia , aún podemos perder 9 de cada 10 servidores web y mantener la red de Stack Exchange en caso de ser necesario. Hay un inconveniente en esto, es muy intensivo en IO (lectura) para nosotros, y el nivel web no se compró con esto en mente (esto suele ser el caso en la mayoría de las empresas). Si bien funciona bien, seguiremos actualizando nuestro nivel web a SSD e implementando algunos otros bits que quedan fuera del puerto .Net para compensar esta deficiencia de hardware (por ejemplo,
NIOFSDirectory
). - El otro inconveniente es que si indexamos todas nuestras bases de datos
n
veces para el nivel web, pero afortunadamente no estamos privados del ancho de banda de la red y el servidor SQL que almacena en caché los resultados hace que esta sea una operación de indexación delta muy rápida cada vez. Con un gran número de servidores web, solo eso puede eliminar esta opción.
Si el índice está centralizado, ¿cómo lo consultaría, dado que solo vive en el sistema de archivos? ¿Tendré que ponerlo de manera efectiva en un recurso compartido de red que todos los servidores web puedan ver?
- Puede consultarlo en un recurso compartido de archivos de cualquier manera, solo asegúrese de que solo uno esté indexando a la vez (
write.lock
, el mecanismo de bloqueo del directorio asegurará esto y un error cuando intente múltiples IndexWriters a la vez). - Tenga en cuenta mis notas anteriores, este es un uso intensivo de IO cuando muchos lectores están volando, por lo que necesita un amplio ancho de banda para su tienda, al menos iSCSI o una fibra SAN, me gustaría ser cauteloso con este enfoque en una Uso de alto tráfico (cientos de miles de búsquedas por día).
- Otra consideración es cómo actualizar / alertar a sus servidores web (o cualquier nivel que lo esté consultando). Cuando
IndexReader
un pase de indexación, deberá volver a abrir susIndexReader
s para obtener el índice actualizado con nuevos documentos. Usamos un canal de mensajería de redis para alertar a quien quiera que el índice se haya actualizado ... cualquier mecanismo de mensajería funcionaría aquí.
¿Existen herramientas preexistentes que poblarán de forma incremental un índice de Lucene en un horario, extrayendo los datos de una base de datos de SQL Server? ¿Sería mejor rodar mi propio servicio aquí?
- Desafortunadamente, no conozco ninguno, pero puedo compartir con ustedes cómo abordé esto.
- Al indexar una tabla específica (similar a un documento en Lucene), agregamos una rowversion de rowversion a esa tabla. Cuando indexamos, seleccionamos en función de la última versión de la fila (un tipo de datos de rowversion , retirado como un bigint ). Elegí almacenar la última fecha del índice y la última versión de la fila indexada en el sistema de archivos a través de un simple archivo .txt por una razón: todo lo demás en Lucene está almacenado allí. Esto significa que si alguna vez hay un gran problema, simplemente puede eliminar la carpeta que contiene el índice y la próxima pasada de indexación se recuperará y tendrá un índice completamente actualizado, simplemente agregue algo de código para controlar que no haya nada que signifique "indexar todo" .
Cuando pregunto por el índice, ¿debería buscar simplemente retroceder un grupo de ID de registro que luego vuelvo a la base de datos para el registro real, o debería apuntar a sacar todo lo que necesito para la búsqueda directamente del índice? ?
- Esto realmente depende de sus datos, para nosotros no es realmente factible almacenar todo en el índice (ni se recomienda esto). Lo que sugiero es que almacene los campos para sus resultados de búsqueda en el índice, y con eso quiero decir lo que necesita para presentar sus resultados de búsqueda en una lista, antes de que el usuario haga clic para ir al [insertar tipo aquí].
- Otra consideración es con qué frecuencia cambian sus datos. Si muchos de los campos en los que no está buscando están cambiando rápidamente, deberá volver a indexar esas filas (documentos) para actualizar su índice, no solo cuando cambie el campo que está buscando.
¿Hay valor en tratar de implementar algo como Solr en este entorno de sabor? Si es así, probablemente le daría su propia * nix VM y la ejecutaría dentro de Tomcat. Pero no estoy seguro de lo que Solr me compraría en este caso.
- Claro que sí, es la búsqueda centralizada de la que estás hablando (con un gran número de búsquedas puedes llegar de nuevo a un límite con una configuración de VM, vigila esto). No hicimos esto porque introdujo mucha (no creemos) complejidad injustificada en nuestra pila de tecnología y en nuestro proceso de compilación, pero para una gran cantidad de servidores web tiene mucho más sentido.
- ¿Qué te compra? rendimiento principalmente, y un servidor (s) de indexación dedicado. En lugar de
n
servidores rastreando un recurso compartido de red (compitiendo también por IO), pueden atacar a un solo servidor que solo atiende solicitudes y resultados a través de la red, sin rastrear el índice, que es mucho más datos que van y vienen ... esto sería local en el (los) servidor (es) de Solr. Además, no está afectando mucho a su servidor SQL, ya que menos servidores están indexando. - Lo que no te compra es tanta redundancia, pero depende de ti lo importante que es esto. Si puede funcionar bien en una búsqueda degradada o sin ella, simplemente haga que su aplicación lo maneje. Si no puede , entonces un servidor Solr de respaldo o más también puede ser una solución válida ... y es posible que otra pila de software se mantenga.