I have a site which has ~3k products and I have to do a search page for the front end. Can anyone recommend the best way to get a list of IPublishedContents back from a partial sku. My current (clearly very wrong) approach looks like this:
var products = Umbraco.TypedContent(10451).Descendants("Product").Where(y => y.GetPropertyValue<ProductDisplay>("product").Sku.Contains(table.searchTerms));
Is there a performant way to link my product documents to the merchello products? Unfortunately I need to get the documents back as I have to display many fields from the product document and I also need to merge the results that come back with a search on the name field for the product documents.
I faced the same challenge when I built my first Mechello shop. I solved that using a customize Examine index.
I added all the necessary information from Merchello on a customized version of the standad External index. All category displays the get the display information from the Examine index.
Using this approach gave me the speed and flexibility of Examine with a little added logic.
if you are interested in this approach I can give you some pointers on the code.
I know there is a lot of code here, but basically it consists of two parts. The SetProductSearchFields method ensures that the nodes referencing the product is reindexed when a product is updated in Merchello. The SetSiteSearchFields method adds the product fields needed for rendering.
I removed some code to reduce complexity, so the code might not work as is. Just ask if you have any questions.
That looks great. I have it compiling in my project. Just trying to get my head around how to actually use examine to do the search now! I'll let you know if I get stuck.
I faced the same problem, it seems those keys are indexed but not searchable.
My dirty workaround is:
Basing on the GatheringNodeData handler provided by Carsten, just add the field you want to search. e.g.
e.Fields.Add("sku_searchable", e.Fields["sku"]);
Then I also identified these extra fields as user fields, so you just search on these searchable index clone instead of the original one.
I want to add one more points, e.g. original "price" & "salesPrice" fields are not assigned with correct type, thus failing the "Range" LuceneQuery. To fix it, I overrided their type to DOUBLE
Searching for products by partial sku and getting IPublishedContent back
I have a site which has ~3k products and I have to do a search page for the front end. Can anyone recommend the best way to get a list of IPublishedContents back from a partial sku. My current (clearly very wrong) approach looks like this:
Is there a performant way to link my product documents to the merchello products? Unfortunately I need to get the documents back as I have to display many fields from the product document and I also need to merge the results that come back with a search on the name field for the product documents.
Thanks
Chris
Hi Chris,
I faced the same challenge when I built my first Mechello shop. I solved that using a customize Examine index.
I added all the necessary information from Merchello on a customized version of the standad External index. All category displays the get the display information from the Examine index.
Using this approach gave me the speed and flexibility of Examine with a little added logic.
if you are interested in this approach I can give you some pointers on the code.
Carsten
Yes please! I had a look at examine but I couldn't work out how to get the merchello products linked with the umbraco document.
Thanks
Chris
I have tried to strip down the code I use to update the index:
public class AppStarting : IApplicationEventHandler
{
private static readonly object s_LockObj = new object();
private static bool s_Ran;
public void OnApplicationStarted(UmbracoApplicationBase umbracoApplication, ApplicationContext applicationContext)
{
if (s_Ran)
return;
lock (s_LockObj)
{
if (s_Ran)
return;
//Add event to allow searching by site section
var indexerSite = ExamineManager.Instance.IndexProviderCollection["ExternalIndexer"];
indexerSite.GatheringNodeData += this.SetSiteSearchFields;
var productIndexerSite = ExamineManager.Instance.IndexProviderCollection["MerchelloProductIndexer"];
productIndexerSite.GatheringNodeData += this.SetProductSearchFields;
s_Ran = true;
}
}
private void SetProductSearchFields(object sender, IndexingNodeDataEventArgs e)
{
// Find documents referencing product
var sku = e.Fields.ContainsKey("productKey") ? e.Fields["productKey"] : null;
if (sku != null)
{
BaseSearchProvider searcher = ExamineManager.Instance.SearchProviderCollection["ExternalSearcher"];
ISearchCriteria criteria = searcher.CreateSearchCriteria(IndexTypes.Content);
IBooleanOperation query = criteria.NodeTypeAlias("ShopProduct");
query = query.And().GroupedOr(new[] { "product" }, sku);
var compiledQuery = query.Compile();
ISearchResults productRowsRaw = searcher.Search(compiledQuery);
foreach (var result in productRowsRaw)
{
ExamineManager.Instance.ReIndexNode(new Document(result.Id).ToXDocument(false).Root, IndexTypes.Content);
}
}
}
private void SetSiteSearchFields(object sender, IndexingNodeDataEventArgs e)
{
//grab the current data from the Fields collection
var path = e.Fields["path"];
//let's get rid of those commas!
path = path.Replace(",", " ");
//add as new field, as path seems to be a reserved word in Lucene
e.Fields.Add("searchPath", path);
if (e.Fields.ContainsKey("product"))
{
var productString = e.Fields["product"];
if (!String.IsNullOrEmpty(productString))
{
var productGuid = new Guid(productString);
var productVariants = Merchello.Core.MerchelloContext.Current.Services.ProductService.GetProductVariantsByProductKey(productGuid).Where(x => x.Available).ToList();
if (productVariants.Any())
{
var minPrice = productVariants.Min(x => x.Price);
var minSalePrice = productVariants.Min(x => x.SalePrice) ?? minPrice;
var manufacturer = productVariants.Max(x => x.Manufacturer);
string modelNumbers = "";
string skus = "";
foreach (var productVariant in productVariants)
{
modelNumbers += productVariant.ManufacturerModelNumber + " ";
skus += productVariant.Sku + " ";
}
e.Fields.Add("price", minPrice.ToString("00000"));
e.Fields.Add("salePrice", minSalePrice.ToString("00000"));
e.Fields.Add("manufacturer", manufacturer);
e.Fields.Add("onSale", productVariants.Any(x => x.OnSale).ToString());
e.Fields.Add("modelNumbers", modelNumbers);
e.Fields.Add("sku", skus);
}
}
}
}
}
I know there is a lot of code here, but basically it consists of two parts. The SetProductSearchFields method ensures that the nodes referencing the product is reindexed when a product is updated in Merchello. The SetSiteSearchFields method adds the product fields needed for rendering.
I removed some code to reduce complexity, so the code might not work as is. Just ask if you have any questions.
Carsten
Just want to add 1 point. In my case, I need to further specify the type (ProductIndexer). i.e.
Otherwise the
doesn't work. I'm not sure why actually but it's what I did as fix.
Hi Carsten,
That looks great. I have it compiling in my project. Just trying to get my head around how to actually use examine to do the search now! I'll let you know if I get stuck.
Thanks
Chris
Hi Carten,
Thank you for your code. I have it working perfectly with very little tweaking.
Thanks
Chris
I have a question. I use your code and this line never return any variants:
But in my merchello product I add SKU, Manufacturer, UPC code, Manufacturer MOdel No.
Can you also paste a line code of how to do the search in my controller, for example get all manufacturers. ?
Thanks
I faced the same problem, it seems those keys are indexed but not searchable. My dirty workaround is:
Basing on the GatheringNodeData handler provided by Carsten, just add the field you want to search. e.g.
Then I also identified these extra fields as user fields, so you just search on these searchable index clone instead of the original one.
I want to add one more points, e.g. original "price" & "salesPrice" fields are not assigned with correct type, thus failing the "Range" LuceneQuery. To fix it, I overrided their type to DOUBLE
is working on a reply...