<style>
.reveal section img {
margin: 15px 0px;
background: none;
border: none;
box-shadow: none;
}
</style>
<!-- .slide: data-background="https://res.cloudinary.com/weroes-aps/image/upload/v1603353529/title_bg_khfshj.png" -->
---
<!-- .slide: data-background="https://res.cloudinary.com/weroes-aps/image/upload/v1603359934/summit_bg_ujtefb.svg" -->
##### Agenda
1. Short recap: What is BOLT?
1. Fine tuning your BOLT queries (9.0+)
1. Elastic Search support (and other providers)
1. Indexing prices with tax and any number of prices (coming in 9.4)
1. New definition and query syntax (coming in 9.4)
---
<!-- .slide: data-background="https://res.cloudinary.com/weroes-aps/image/upload/v1603359934/summit_bg_ujtefb.svg" -->
## Short recap: What is BOLT?
Fast product retrieval is key on any ecommerce site
---
<!-- .slide: data-background="https://res.cloudinary.com/weroes-aps/image/upload/v1603359934/summit_bg_ujtefb.svg" -->
## The BOLT Team
David Kelemen 
 Daniel Berg Frederiksen
Lukas Vaclavek 
 Petr Ilnytsky
---
<!-- .slide: data-background="https://res.cloudinary.com/weroes-aps/image/upload/v1603359934/summit_bg_ujtefb.svg" -->
## Short recap: What is BOLT?
* Fast retrieval & search
* Familiar
* Extensible
---
<!-- .slide: data-background="https://res.cloudinary.com/weroes-aps/image/upload/v1603359934/summit_bg_ujtefb.svg" -->
##### Design goals of BOLT
## Fast
No need to query the SQL db in product listings
Tested on realistic databases
---
<!-- .slide: data-background="https://res.cloudinary.com/weroes-aps/image/upload/v1603359934/summit_bg_ujtefb.svg" -->
##### Design goals of BOLT
## Extensible
Powered by Lucene by default
Multiple search providers
---
<!-- .slide: data-background="https://res.cloudinary.com/weroes-aps/image/upload/v1603359934/summit_bg_ujtefb.svg" -->
##### Design goals of BOLT
## Familiar
One interface across providers
```csharp$
Products
.Find()
.Where(c => c.DisplayName == Match.Fuzzy("shoo"))
.OrderBy(c => c.PricesInclTax["EUR"])
.ToList()
```
---
<!-- .slide: data-background="https://res.cloudinary.com/weroes-aps/image/upload/v1603359934/summit_bg_ujtefb.svg" -->
## Let's talk "Fast"
With BOLT, it's hard to degrade performance, but not impossible
First advice: Limit the number of queries
---
<!-- .slide: data-background="https://res.cloudinary.com/weroes-aps/image/upload/v1603359934/summit_bg_ujtefb.svg" -->
## Fine-tuning your BOLT queries (9.0+)
If you do need to optimize a query, we can help!
---
<!-- .slide: data-background="https://res.cloudinary.com/weroes-aps/image/upload/v1603359934/summit_bg_ujtefb.svg" -->
```
3644 17:20:42 INFO
Running ToList() query on index at: file:///C:/inetpub/wwwroot/sitecore.9.3.0.local/App_Data/Ucommerce/Indexes/A/LuceneDiskIndex-Product-AvenueProductIndexDefinition_7b2c2447f347/en [0 msec]
- Where clauses: p => (p.Categories.Contains(value(Ucommerce.Api.CatalogLibrary+<>c__DisplayClass36_0).categoryId.Value) AndAlso (Convert(p.ProductType) != 3)) [0 msec]
- Native query: +(+Categories:a2262f1f-e212-4b47-882d-aec58aec8abd -ProductType:3) [1 msec]
- Done searching [8 msec]
= Hits: 1 of 1 total. [8 msec]
= Spent 3 msecs retrieving docs [11 msec]
= Spent 4 msecs unwrapping docs [15 msec]
LuceneSearch`1.ToList <= CatalogLibrary.GetProducts <= CategoryController.GetProductGuidsInFacetsAndSelectedProductOnSitecoreItem <= CategoryController.Rendering <= ControllerRunner.ExecuteController <= ControllerRunner.Execute <= ExecuteRenderer.Render <= ExecuteRenderer.Process <= CorePipeline.Run <= DefaultCorePipelineManager.Run
```
---
<!-- .slide: data-background="https://res.cloudinary.com/weroes-aps/image/upload/v1603359934/summit_bg_ujtefb.svg" -->
### Dissecting a log entry
---
<!-- .slide: data-background="https://res.cloudinary.com/weroes-aps/image/upload/v1603359934/summit_bg_ujtefb.svg" -->
Which index are we using?
```
Running ToList() query on index at:
file:///C:/inetpub/wwwroot/sitecore.9.3.0.local/App_Data/
Ucommerce/Indexes/A/
LuceneDiskIndex-Product-
AvenueProductIndexDefinition_7b2c2447f347/en
[0 msec]
```
---
<!-- .slide: data-background="https://res.cloudinary.com/weroes-aps/image/upload/v1603359934/summit_bg_ujtefb.svg" -->
Translating the query
```
- Where clauses: p =>
(p.Categories.Contains(value(
Ucommerce.Api.CatalogLibrary+<>c__DisplayClass36_0)
.categoryId.Value)
AndAlso (Convert(p.ProductType) != 3))
[0 msec]
- Native query:
+(+Categories:a2262f1f-e212-4b47-882d-aec58aec8abd
-ProductType:3)
[1 msec]
```
---
<!-- .slide: data-background="https://res.cloudinary.com/weroes-aps/image/upload/v1603359934/summit_bg_ujtefb.svg" -->
Searching
```
- Done searching [8 msec]
= Hits: 1 of 1 total. [8 msec]
```
---
<!-- .slide: data-background="https://res.cloudinary.com/weroes-aps/image/upload/v1603359934/summit_bg_ujtefb.svg" -->
Retrieving data
```
= Spent 3 msecs retrieving docs [11 msec]
= Spent 4 msecs unwrapping docs [15 msec]
```
---
<!-- .slide: data-background="https://res.cloudinary.com/weroes-aps/image/upload/v1603359934/summit_bg_ujtefb.svg" -->
The mini stack trace
```
LuceneSearch`1.ToList <=
CatalogLibrary.GetProducts <=
CategoryController.GetProductGuidsInFacetsAndSelectedProductOnSitecoreItem <=
CategoryController.Rendering <=
ControllerRunner.ExecuteController <=
ControllerRunner.Execute <=
ExecuteRenderer.Render <=
ExecuteRenderer.Process <=
CorePipeline.Run <=
DefaultCorePipelineManager.Run
```
---
<!-- .slide: data-background="https://res.cloudinary.com/weroes-aps/image/upload/v1603359934/summit_bg_ujtefb.svg" -->
#### There's more to "Fast"
## The open source Ucommerce Seeder tool
---
<!-- .slide: data-background="https://res.cloudinary.com/weroes-aps/image/upload/v1603359934/summit_bg_ujtefb.svg" -->

---
<!-- .slide: data-background="https://res.cloudinary.com/weroes-aps/image/upload/v1603359934/summit_bg_ujtefb.svg" -->
##### What are the estimated dimensions of your data?
```json
{
"Products": 500000,
"Stores": 3,
"CatalogsPerStore": 5,
"CategoriesPerCatalog": 100,
"AverageVariantsPerProduct": 10,
"AverageProductsPerCategory": 1000,
"Currencies": 10,
"Languages": 7,
"PriceGroups": 3000,
}
```
---
<!-- .slide: data-background="https://res.cloudinary.com/weroes-aps/image/upload/v1603359934/summit_bg_ujtefb.svg" -->
Seeding can help you get realistic queries and reach your performance goals before go-live
https://github.com/Ucommercenet/Ucommerce-Seeder/
---
<!-- .slide: data-background="https://res.cloudinary.com/weroes-aps/image/upload/v1603359934/summit_bg_ujtefb.svg" -->
## Elastic Search provider
##### Motivation:
Even higher speed
Scalability
Maintenance
---
<!-- .slide: data-background="https://res.cloudinary.com/weroes-aps/image/upload/v1603359934/summit_bg_ujtefb.svg" -->
## Elastic Search provider
Just switch provider and re-index
Re-use existing queries
Option to pass through NEST or JSON queries
We aim for v9.4
---
<!-- .slide: data-background="https://res.cloudinary.com/weroes-aps/image/upload/v1603359934/summit_bg_ujtefb.svg" -->
## Your search provider?
Solr?
Azure?
Amazon?
Google?
...?
---
<!-- .slide: data-background="https://res.cloudinary.com/weroes-aps/image/upload/v1603359934/summit_bg_ujtefb.svg" -->
### How to make a provider?
Right now: Somewhat difficult
Future: Easy
---
<!-- .slide: data-background="https://res.cloudinary.com/weroes-aps/image/upload/v1603359934/summit_bg_ujtefb.svg" -->
#### How do I know when I'm done?
### You need a test suite!
---
<!-- .slide: data-background="https://res.cloudinary.com/weroes-aps/image/upload/v1603359934/summit_bg_ujtefb.svg" -->
### Conclusion
It's possible to write your own provider
It will be easier in the future:
* One test suite across providers
* Fewer interfaces
---
<!-- .slide: data-background="https://res.cloudinary.com/weroes-aps/image/upload/v1603359934/summit_bg_ujtefb.svg" -->
## Facetting prices with tax and any number of prices
#### coming in 9.4
---
<!-- .slide: data-background="https://res.cloudinary.com/weroes-aps/image/upload/v1603359934/summit_bg_ujtefb.svg" -->
### Before
Limited to **one** price field with multiple price groups
(by default `Product.UnitPrices`)
---
<!-- .slide: data-background="https://res.cloudinary.com/weroes-aps/image/upload/v1603359934/summit_bg_ujtefb.svg" -->
### Before
```csharp
var productsInCategory = productIndex.Find()
.PriceGroup(CatalogContext.CurrentPriceGroup)
.Where(facets)
.ToFacets();
```
---
<!-- .slide: data-background="https://res.cloudinary.com/weroes-aps/image/upload/v1603359934/summit_bg_ujtefb.svg" -->
### After
```csharp
var productsInCategory = productIndex.Find()
.Where(facets)
.ToFacets();
```
---
<!-- .slide: data-background="https://res.cloudinary.com/weroes-aps/image/upload/v1603359934/summit_bg_ujtefb.svg" -->
## New possibilities
---
<!-- .slide: data-background="https://res.cloudinary.com/weroes-aps/image/upload/v1603359934/summit_bg_ujtefb.svg" -->
### Before
```csharp
class MyIndexDefintion : IIndexDefinition<Product>
{
public MyIndexDefintion()
{
...
this.PricesField(p => p.UnitPrices);
...
...
}
}
```
---
<!-- .slide: data-background="https://res.cloudinary.com/weroes-aps/image/upload/v1603359934/summit_bg_ujtefb.svg" -->
### After
```csharp
class MyIndexDefintion : IIndexDefinition<Product>
{
public MyIndexDefintion()
{
...
this.Field(p => p.UnitPrices).Facet();
this.Field(p => p.PricesInclTax).Facet();
this.Field(p => p.Tax).Facet();
...
...
}
}
```
---
<!-- .slide: data-background="https://res.cloudinary.com/weroes-aps/image/upload/v1603359934/summit_bg_ujtefb.svg" -->
### Facetting Prices Summary
Any number of dictionary type fields supported
Not just for monetary amounts
:warning: Breaking change -- you will need to change your code a few places
Coming in 9.4
---
<!-- .slide: data-background="https://res.cloudinary.com/weroes-aps/image/upload/v1603359934/summit_bg_ujtefb.svg" -->
## New definition syntax
#### Coming in 9.4
---
<!-- .slide: data-background="https://res.cloudinary.com/weroes-aps/image/upload/v1603359934/summit_bg_ujtefb.svg" -->
#### Chaining syntax
```csharp
this.Field(p => p.Description)
.FullText()
.DontStore();
```
---
<!-- .slide: data-background="https://res.cloudinary.com/weroes-aps/image/upload/v1603359934/summit_bg_ujtefb.svg" -->
#### Chaining syntax
```csharp
this.Field(p => p.PricesInclTax["USD 7 PCT VAT"])
.Facet()
.DisplayName("Price in $");
```
---
<!-- .slide: data-background="https://res.cloudinary.com/weroes-aps/image/upload/v1603359934/summit_bg_ujtefb.svg" -->
#### Range Facets
```csharp
this.Field("ShoeSizeEU", typeof(int))
.Facet()
.Range(20,27)
.Range(27,32)
.Range(32,37)
.Range(37,42)
.Range(42,49)
```
---
<!-- .slide: data-background="https://res.cloudinary.com/weroes-aps/image/upload/v1603359934/summit_bg_ujtefb.svg" -->
#### Auto Range Facets
```csharp
this.Field(p => p.PricesInclTax["EUR"])
.Facet()
.AutomaticRanges(5, 10)
```
---
<!-- .slide: data-background="https://res.cloudinary.com/weroes-aps/image/upload/v1603353911/summit_bg_ekjequ.png" -->
##### You've been watching, in order of appearance:
### Use the seeder tool to test your performance before production
### Use the log entries to fine tune your search queries
---
<!-- .slide: data-background="https://res.cloudinary.com/weroes-aps/image/upload/v1603353911/summit_bg_ekjequ.png" -->
##### Look forward to
### Elastic Search
### Multiple prices fields with multiple price groups
### Leaner definition and query syntax
---
<!-- .slide: data-background="https://res.cloudinary.com/weroes-aps/image/upload/v1603359934/summit_bg_ujtefb.svg" -->
#### Thank your for your attention!
## Time for questions?
---
<!-- .slide: data-background="https://res.cloudinary.com/weroes-aps/image/upload/v1603358733/psscreensaver2_grxrkm.jpg" -->
{"metaMigratedAt":"2023-06-15T14:27:06.323Z","metaMigratedFrom":"YAML","title":"BOLT Deep Dive slides","breaks":true,"slideOptions":"{\"theme\":\"night\",\"transition\":\"fade\",\"allottedMinutes\":18}","contributors":"[{\"id\":\"7e34ea49-c725-4e89-bb55-e9383bc476f9\",\"add\":35151,\"del\":22550}]"}