c# solr sitecore sitecore7.5

c# - ¿Cómo controlo la prioridad de las consultas anidadas en Sitecore ContentSearch con el proveedor Solr?



sitecore7.5 (3)

Detalles de la versión: Estoy trabajando con Sitecore 7.5 build 141003, utilizando Solr v4.7 como servidor de búsqueda / indexación. También estoy usando el proveedor estándar de Sitecore Solr sin indexadores personalizados.

Objetivo objetivo: estoy usando Sitecore ContentSearch LINQ con PredicateBuilder para compilar algunas consultas flexibles y anidadas. Actualmente, debo buscar dentro de un "elemento raíz" específico, excluyendo las plantillas con "carpeta" en su nombre, también excluyendo los elementos con "/ prueba" en su ruta. En algún momento, el "elemento raíz" podría ser más de un elemento, y la ruta también podría contener (actualmente solo "/ prueba". En esos casos, la idea es usar PredicateBuilder para construir un predicado externo "AND" con inner " O "s" para los múltiples "Root item" y exclusiones de ruta.

Problema: en este momento, estoy lidiando con un problema relacionado con el orden de anidación y las prioridades para estos predicados / condiciones. He estado probando varios enfoques y combinaciones, pero el problema que sigo encontrando es! TemplateName.Contains y Item ["_ fullpath"]. Contiene prioridad sobre los Paths.Contains, que termina dando como resultado 0 resultados cada vez.

Estoy usando Search.log para verificar el resultado de la consulta, y he estado probando manualmente contra el administrador de Solr, ejecutando consultas en su contra para comparar los resultados. A continuación, encontrará ejemplos de las combinaciones que he intentado usar Sitecore Linq y las consultas que producen para Solr.

Muestra del código original:

Prueba original con lista para elementos raíz

// sometimes will be 1, sometimes will be multiple var rootItems = new List<ID> { pathID }; // simplified to 1 item for now var query = context.GetQueryable<SearchResultItem>(); var folderFilter = PredicateBuilder.True<SearchResultItem>().And(i => !i.TemplateName.Contains("folder") && !i["_fullpath"].Contains("/testing")); var pathFilter = PredicateBuilder.False<SearchResultItem>(); pathFilter = rootItems.Aggregate(pathFilter, (current, id) => current.Or(i => i.Paths.Contains(id))); folderFilter = folderFilter.And(pathFilter); query.Filter(folderFilter).GetResults();

Salida de consulta: (-_templatename: (* folder *) AND -_fullpath: (* / testing *)) AND _path: (730c169987a44ca7a9ce294ad7151f13)

Como puede ver en el resultado anterior, hay un conjunto interno de paréntesis alrededor de los dos filtros "no contiene" que tiene prioridad sobre el de Ruta uno. Cuando ejecuto esta consulta exacta en el administrador de Solr, devuelve 0 resultados. Sin embargo, si elimino el paréntesis interno para que quede todo un solo conjunto "Y", devuelve los resultados esperados.

Probé esto más a fondo con diferentes combinaciones y enfoques para PredicateBuilder, y cada combinación da como resultado la misma consulta. Incluso intenté agregar dos filtros individuales ("query.Filter (pred1) .Filter (pred2)") a mi objeto de consulta principal, y da como resultado el mismo resultado.

Muestras de código adicionales:

Alt. 1 - Agregar "Paths.Contains" al filtro de carpeta directamente

var query = context.GetQueryable<SearchResultItem>(); var folderFilter = PredicateBuilder.True<SearchResultItem>().And(i => !i.TemplateName.Contains("folder") && !i["_fullpath"].Contains("/testing")); folderFilter = folderFilter.And(i => i.Paths.Contains(pathID)); query.Filter(folderFilter).GetResults();

Salida de consulta: (-_templatename: (* folder *) AND -_fullpath: (* / testing *)) AND _path: (730c169987a44ca7a9ce294ad7151f13)

Alt 2 : dos predicados unidos al primero

var query = context.GetQueryable<SearchResultItem>(); var folderFilter = PredicateBuilder.True<SearchResultItem>().And(i => !i.TemplateName.Contains("folder") && !i["_fullpath"].Contains("/testing")); var pathFilter = PredicateBuilder.False<SearchResultItem>().Or(i => i.Paths.Contains(pathID)); folderFilter = folderFilter.And(pathFilter); query.Filter(folderFilter).GetResults();

Salida de consulta: (-_templatename: (* folder *) AND -_fullpath: (* / testing *)) AND _path: (730c169987a44ca7a9ce294ad7151f13)

Alt 3 : dos predicados "internos", uno para "No" y otro para "Rutas" unidas a un predicado externo

var query = context.GetQueryable<SearchResultItem>(); var folderFilter = PredicateBuilder.True<SearchResultItem>().And(i => !i.TemplateName.Contains("folder") && !i["_fullpath"].Contains("/testing")); var pathFilter = PredicateBuilder.False<SearchResultItem>().Or(i => i.Paths.Contains(pathID)); var finalPredicate = PredicateBuilder.True<SearchResultItem>().And(folderFilter).And(pathFilter); query.Filter(finalPredicate).GetResults();

Salida de consulta: (-_templatename: (* folder *) AND -_fullpath: (* / testing *)) AND _path: (730c169987a44ca7a9ce294ad7151f13)

Conclusión: en última instancia, lo que busco es una forma de controlar la priorización de estas consultas / condiciones anidadas, o cómo puedo construirlas para poner primero las rutas y después los filtros "No". Como se mencionó, hay condiciones en las que tendremos múltiples "elementos raíz" y múltiples exclusiones de ruta donde necesito consultar algo más parecido a:

(-_templatename: (* folder *) AND -_fullpath: (* / testing *) AND (_path: (730c169987a44ca7a9ce294ad7151f13) O _path: (12c1aa7f60fa4e8d9f0a983bbbb40d8b)))

O

(-_templatename: (* folder *) AND -_fullpath: (* / testing *) AND (_path: (730c169987a44ca7a9ce294ad7151f13)))

Ambas consultas devuelven los resultados que espero / necesito cuando los ejecuto directamente en el administrador de Solr. Sin embargo, parece que no se me ocurre un enfoque u orden de las operaciones usando Sitecore ContentSearch Linq para generar una consulta de esta manera.

¿Alguien más tiene experiencia con cómo puedo lograr esto? Dependiendo de la sugerencia, también estoy dispuesto a armar esta parte de la consulta sin Sitecore Linq, si puedo casarme con IQueryable para llamar a "GetFacets" y "GetResults".

Actualización: No incluí todas las revisiones que he hecho porque SO probablemente me mataría por cuánto tiempo esto llegaría. Dicho esto, probé otra pequeña variación en mi ejemplo original (arriba) con un resultado similar al de los otros:

var folderFilter = PredicateBuilder.True<SearchResultItem>().And(i => !i.TemplateName.Contains("folder")).And(i => !i["_fullpath"].Contains("/testing")); var rootItems = new List<ID> { pathID, path2 }; // or paths separately var pathFilter = PredicateBuilder.False<SearchResultItem>(); pathFilter = rootItems.Aggregate(pathFilter, (current, id) => current.Or(i => i.Paths.Contains(id))); var finalPredicate = folderFilter.And(pathFilter); var query = context.GetQueryable<SearchResultItem>(); query.Filter(finalPredicate).GetResults();

Query Output: ((-_templatename: (* folder *) AND -_fullpath: (* / testing *)) AND (_path: (730c169987a44ca7a9ce294ad7151f13) O _path: (12c1aa7f60fa4e8d9f0a983bbbb40d8b)))

Y todavía son esos paréntesis internos alrededor de las condiciones "_templatename" y "_fullpath" que causan problemas.

Gracias.


De acuerdo, planteé esta pregunta aquí y también envié la situación al soporte de Sitecore, y acabo de recibir una respuesta y algo de información adicional.

De acuerdo con la wiki de Solr ( http://wiki.apache.org/solr/FAQ ), en la sección "Búsqueda", la pregunta ¿Por qué ''foo AND -baz'' coincide con los documentos, pero ''foo AND (-bar)'' no? responde por qué los resultados están volviendo 0.

Las consultas booleanas deben tener al menos una expresión "positiva" (es decir, DEBE o DEBERÍA) para coincidir. Solr intenta ayudar con esto, y si se le pide que ejecute una BooleanQuery que contiene solo cláusulas negativas en el nivel superior , agrega una consulta match all docs (es decir::)

Si el BoolenQuery de nivel superior contiene en algún lugar dentro de él una BooleanQuery anidada que contiene solo cláusulas negadas, esa consulta anidada no se modificará y (por definición) no coincidirá con ningún documento, si es necesario, eso significa que el la consulta no coincidirá.

No estoy seguro de qué se está haciendo completamente para construir la consulta en el proveedor de Sitecore Solr, o por qué están agrupando los elementos negativos en una consulta anidada, pero la consulta anidada con resultados negativos solo arroja 0 resultados como se esperaba, según Solr. doc. El truco, entonces, es agregar una consulta "coincidir todo" (*: *) a la subconsulta.

En lugar de tener que hacer esto manualmente para cualquier consulta que creo que pueda encontrar esta situación, el representante de soporte proporcionó una DLL de parche para reemplazar el proveedor, que modificará automáticamente la consulta anidada para remediar esto.

También registraron esto como un error y proporcionaron el número de referencia 398622 para el problema.

Ahora, la consulta resultante se ve así:

((-_templatename:(*folder*) AND -_fullpath:(*/testing*) AND *:*) AND _path:(730c169987a44ca7a9ce294ad7151f13))

o, para múltiples consultas:

((-_templatename:(*folder*) AND -_fullpath:(*/testing*) AND *:*) AND (_path:(730c169987a44ca7a9ce294ad7151f13) OR _path:(12c1aa7f60fa4e8d9f0a983bbbb40d8b)))

Y los resultados regresan como se esperaba. Si alguien más se encuentra con esto, usaría el número de referencia con el soporte de Sitecore y vería si pueden proporcionar el parche. También deberá actualizar el proveedor utilizado en sus archivos de configuración Solr.Index y Solr.Indexes.Analytics.


He intentado el siguiente código y produjo su consulta de salida necesaria. El truco fue usar PredicateBuilder.True () al crear una consulta de filtro de ruta. No estoy seguro de si ese es un comportamiento normal de la API de búsqueda de contenido, o es un error.

var query = context.GetQueryable<Sitecore.ContentSearch.SearchTypes.SearchResultItem>(); var folderFilter = PredicateBuilder.True<SearchResultItem>().And(i => !i.TemplateName.Contains("folder") && !i["_fullpath"].Contains("/testing")); var pathFilter = PredicateBuilder.True<SearchResultItem>(); pathFilter = pathFilter.Or(i => i.Paths.Contains(Path1) || i.Paths.Contains(Path2)); folderFilter = folderFilter.And(pathFilter);


Si las 2 muestras de trabajo al final son correctas, entonces necesita separar AND las partes de su consulta separadamente, en lugar de incluir 2 instrucciones en una sola llamada, que es lo que está causando la anidación de la parte inicial de su extracto:

// the path part of the query. OR together all the locations var pathFilter = PredicateBuilder.False<SearchResultItem>(); pathFilter = pathFilter.Or(i => i.Paths.Contains(pathID)); pathFilter = pathFilter.Or(i => i.Paths.Contains(pathID2)); ... // the exclusions, build them up seprately var query = PredicateBuilder.True<SearchResultItem>(); query = query.And(i => !i.TemplateName.Contains("folder")); query = query.And(i => !i["_fullpath"].Contains("/testing")); // join both parts together query = query.And(pathFilter);

Esto debería darte (pseudo):

!templateName.Contains("folder") AND !_fullpath.Contains("/testing") AND (path.Contains(pathID1) || path.Contains(pathID2))

Si está intentando excluir ciertas plantillas, puede excluirlas de su índice en primer lugar actualizando la configuración ExcludeTemplate en Sitecore.ContentSearch.Solr.DefaultIndexConfiguration.config . No tendrá que preocuparse por excluirlo específicamente en la consulta, entonces:

<exclude hint="list:ExcludeTemplate"> <MyTemplateId>{11111111-1111-1111-1111-111111111111}</MyTemplateId> <MyTemplateId>{22222222-2222-2222-2222-222222222222}</MyTemplateId> </exclude>