Sitecore Content Search PredicateBuilder vs IEnumerable - lucene

I'm having problem with querying IEnumerable computed index field. Im using Sitecore 7.2 upd2, Lucene, ContentSearch and PredicateBuilder.
I'm trying to query product prices which are available under products section. There is some heavy Logic to find available products so I decided to put all available product prices in computed field. Unfortuantelly it looks like I'm unable to query prices list with PredicateBuilder.
My query looks like this:
predicate = predicate.And(p => p.Prices.Any(x => x >= priceFrom && x <= priceTo));
field configuration in index config:
<field fieldName="Prices" storageType="YES" indexType="TOKENIZED" vectorType="NO" boost="1f" type="System.Collections.Generic.IEnumerable`1[System.Int32]" settingType="Sitecore.ContentSearch.LuceneProvider.LuceneSearchFieldConfiguration, Sitecore.ContentSearch.LuceneProvider" />
and that's my error:
Invalid Method Call Argument Type: Field - FieldNode - Field: prices - System.Collections.Generic.IEnumerable`1[[System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]. Only constant arguments is supported.
Any Ideas?

The error stems from parameter of the Any() method call.
Sitecore Content Search LINQ has some limitations. One of them is that methods only accept "constant expressions" (objects) as parameters. You are passing a "lamda expression" as a parameter for the Any method.

I would suggest indexing both the min and max price for each product as separate computed fields (decimal) in the index.
This would greatly simplify your query:
var results = context.GetQueryable<ProductSearchResultItem>
.Where(p => p.MinPrice >= myPrice)
.Where(p => p.MaxPrice <= myPrice)
.GetResults();

Related

Solr Schemaless Mode creating fields as MultiValued

I'm using Solr 6.1 in Schemaless Mode. After creating a collection and indexing a sample data the fields created were all set to have MultiValued = true, except for unique id.
The problem is when querying this data using SolrNet it wouldn't map the result to the model correctly. The queried results is returned as an array and require all my properties in the model to be updated to ICollection type.
Is there anyway we can set these field to MultiValued = false when indexing the sample data?
An example to illustrate the problem:
1) Index a sample of the following model in Schemaless Mode:
public class TestModel
{
[SolrUniqueKey("id")]
public int Id { get; set; }
[SolrField("guid")]
public Guid Guid { get; set; }
}
2) Solr's managed-schema file will be added with the following fields
<field name="guid" type="strings"/>
<field name="id" type="string" multiValued="false" indexed="true" required="true" stored="true"/>
3) Error during querying / mapping of the model
Object of type 'System.Collections.ArrayList' cannot be converted to type
The schemaless mode makes everything multiValued as it does not know if you have single values followed by multivalued values for the same field. So it makes all fields multivalued and also upgrades numeric types to the largest.
This is easily adjustable if you know your domain well. The whole mapping chain is defined in the solrconfig.xml's update request processor chain (add-unknown-fields-to-the-schema) and you can change the type mapping from multivalued type to an equivalent single valued type. For strings, you change the value in the defaultFieldType.

Search Predicate Builder

I am using Lucene search with Sitecore 7.2 and using predicate builder to search for data. I have included a computed field in the index which is a string. When I search on that field using .Contains(mystring), it fails when there is 'and' present in mystring. If there is no 'and' in the mystring it works.
Can you please suggest me anything?
Lucene by default, when the field and query is processed, will strip out what are called "stop words" such as and and the etc.
If you dont want this behaviour you can add an entry into the fieldMap section of your configuration to tell Sitecore how to process the field ...
<fieldNames hint="raw:AddFieldByFieldName">
<field fieldName="YOURFIELDNAME" storageType="YES" indexType="UN_TOKENIZED" vectorType="NO" boost="1f" type="System.String" settingType="Sitecore.ContentSearch.LuceneProvider.LuceneSearchFieldConfiguration, Sitecore.ContentSearch.LuceneProvider">
<analyzer type="Sitecore.ContentSearch.LuceneProvider.Analyzers.LowerCaseKeywordAnalyzer, Sitecore.ContentSearch.LuceneProvider" />
</field>
...
</fieldNames>
.. this example tells Sitecore, for that field, to not tokenize and also to put everything into lowercase. You can change to different analyzers to get the results you want.
You can try setting the indexType to TOKENIZED but still using the LowerCaseKeywordAnalyzer as another combination. UN_TOKENIZED will mean that your string will be processed as a single token which may not be what you want.
I have solved it, taking a hint from #Stephen Pope 's reply. In order to make your computed field untokenized you have to add it to both raw:AddFieldByFieldName and AddComputedIndexField.
See link below
http://www.sitecore.net/Community/Technical-Blogs/Martina-Welander-Sitecore-Blog/Posts/2013/09/Sitecore-7-Search-Tips-Computed-Fields.aspx

Does linq to sharepoint support document libraries?

I have a document libraries. I want to filter the documents based on some of the filter conditions. Its really difficult to generate the Caml query dynamically which will give the actual result depending on the filter values.
The filter values are the columns from Document libraries. Linq to Sharepoint support List, but is there anyway by which i can query document libraries too?
You can use Linq To Sharepoint after using the SPMetal tool to generate your entities.
http://www.codeproject.com/Articles/399927/SharePoint-2010-LINQ-and-SPMetal
This is an example of what Sharepoint Link looks like:
using (SiteEntitiesDataContext context = new SiteEntitiesDataContext("http://appes-pc"))
{
var result = context.Manager.Where(m => m.Country == "USA");
foreach (ManagerItem manager in result)
{
Console.WriteLine(manager.Name);
}
}
Or alternatively if you want to use CAML there is a very good CAML builder utility called:
Camlex.NET - http://camlex.codeplex.com/
So this:
<Where>
<Eq>
<FieldRef Name="Status" />
<Value Type="Text">Completed</Value>
</Eq>
</Where>
Can be written as:
string caml =
Camlex.Query()
.Where(x => (string)x["Status"] == "Completed").ToString();

Solr no search results on new field

I added a multivalue field to schema.xml as follows:
<field name="fieldsharedsite" type="string" indexed="true" stored="false" multiValued="true" />
<field name="fieldsharedchannelnew" type="string" indexed="true" stored="false" multiValued="true" />
When I search for a document contents, I get the following result:
<fieldsharedsite><item key="0">33</item></fieldsharedsite>
<fieldsharedchannelnew><item key="0">52</item></fieldsharedchannelnew>
so I am sure fieldsharedchannelnew is in the results
When I do the following search:
q=fieldsharedsite:33
I do get the document
but when I do
q=fieldsharedchannelnew:52
I don't get any results.
fieldsharedsite has been here for a while and I'm trying to add fieldsharedchannelnew.
I did reindex all the content but did not help the search.
If I look at the schema browser, I have for fieldsharedsite:
Field Type: string
Properties: Indexed, Multivalued, Omit Norms, Sort Missing Last
Schema: Indexed, Multivalued, Omit Norms, Sort Missing Last
Index: (unstored field)
Index Analyzer: org.apache.solr.schema.FieldType$DefaultAnalyzer
Query Analyzer: org.apache.solr.schema.FieldType$DefaultAnalyzer
Docs: 902
and for fieldsharedchannnelnew I have:
Field Type: string
Properties: Indexed, Multivalued, Omit Norms, Sort Missing Last
Index Analyzer: org.apache.solr.schema.FieldType$DefaultAnalyzer
Query Analyzer: org.apache.solr.schema.FieldType$DefaultAnalyzer
What step did I miss in adding the fieldsharedchannelnew index? Why its not returning any results when I search for it?
The schema browser result for the field fieldsharedchannnelnew does not indicate it is populated in the documents.
the Docs information is missing, as for fieldsharedsite which shows it exists in 902 docs.
Field Type: string
Properties: Indexed, Multivalued, Omit Norms, Sort Missing Last
Index Analyzer: org.apache.solr.schema.FieldType$DefaultAnalyzer
Query Analyzer: org.apache.solr.schema.FieldType$DefaultAnalyzer
When I search for a document contents, I get the following result:
<fieldsharedsite><item key="0">33</item></fieldsharedsite>
<fieldsharedchannelnew><item key="0">52</item></fieldsharedchannelnew>
As the fields are not stored, the fields would not be returned with the results.
Is this the data you are feeding Solr ? how do they appear in results ?
Are you using value as is or want to use copyfield ?
You may mark the fields as stored and reindex the contents and check if they are returned with the results and the schema browser shows the Docs information.
If so, you should be able to search it as well.

HQL: Querying dynamic-component property

If I have a mapping like this:
<class name="Library" table="Libraries">
...
<dynamic-component name="Annotations">
<property name="LibraryResolver.AlgorithmVersion" column="`LibraryResolver.AlgorithmVersion`" type="Int32" />
</dynamic-component>
</class>
How should I write HQL or Linq-to-NHibernate query for all libraries where LibraryResolver.AlgorithmVersion is greater than a given value?
The HQL query below maybe along the lines you are looking for
from Library as lib
where lib.Annotations.LibraryResolver.AlgorithmVersion > 2
If you're using nhibernate, have you tried out the NHibernate LambdaExtensions? This library provides a set of extensions methods over the Criteria and DetachedCriteria apis which removes the need of magic strings when querying using the above two api.
Below is an example of how one might use NHibernate Detached Criteria query with the mentioned LambdaExtensions library
Answer answerAlias = null;
var actual = DetachedCriteria.For<Survey>()
.Add<Survey>( s => s.Status == SurveyStatus.Complete )
.Add<Questionnaire>( q => q.Id == questionnaireId )
.CreateAlias<Survey>( s => s.Answers, () => answerAlias )
.SetProjection( LambdaProjection.Property( () => answerAlias.Id ) );
I don't know whether this helps but when I use the Criteria API (in Java) it just works. Haven't tried with HQL though.
<dynamic-component name="values">
<property name="dynamicNameValue" column="ATTRIBUTE_1" type="string"/>
<property name="dynamicNumber" column="ATTRIBUTE_4" type="integer"/>
</dynamic-component>
Criteria criteria = session.createCriteria(DynamicAttributes.class)
.add(Expression.eq("values.dynamicNumber", 2));
Just some thought: could it be that the problem is that the name ('LibraryResolver.AlgorithmVersion') you're passing contains a dot? Maybe post some code you already attempted?