GETTING STARTED WITH
ELASTICSEARCH ON WINDOWS
AND .NET WITH NEST
A short introduction

Oslo/NNUG Meetup
Tomas Jansson
29/01/2014
THIS IS ME

Tomas Jansson
Manager & Group Lead .NET
BEKK Oslo
@TomasJansson
tomas.jansson@bekk.no
github.com/mastoj
blog.tomasjansson.com
TL;DR;

https://github.com/mastoj/NestDemo
Getting started with Elasticsearch and .NET
Getting started with Elasticsearch and .NET
AUDIENCE

N00b

Expert

N00b

Expert
BACKGROUND

This is the data and we need this new application
THE MASTERPLAN
WHAT I WANT TO SHOW YOU IS...

Elasticsearch is awesome
Indexing using NEST

Querying using NEST
... not about advanced elasticsearch hosting
Getting started with Elasticsearch and .NET
INSTALLATION

Great news, install as a service added in 0.90.5

Powershell to
the rescue
NEST

Abstraction
over
Elasticsearch

There is an low level abstraction as well called RawElasticClient
NEST

Abstraction
Fluent &
Strongly
over
Elasticsearch
typed
Functional C#
FUNC DEMO

C:Devgit> scriptcs
scriptcs (ctrl-c or blank to exit)

> Func<int, int, int> add = (x, y) => x + y;
> add(1, 3)
4

Func  executable
SIMPLE EXPRESSION DEMO

> using System.Linq.Expressions;
> Expression<Func<int, int, int>> addExpr = (x, y) => x + y;
> addExpr(1, 3)

Expression  ”function description”

(1,1): error CS1955: Non-invocable member 'addExpr' cannot be used like a method.
> var binExpr = addExpr.Body as BinaryExpression;
> Console.WriteLine(binExpr);
(x + y)
> var add2 = addExpr.Compile();
> add2(3, 1);
4
MORE COMPLEX EXPRESSION DEMO

> public class SomeClass { public string MyString { get; set; } }
> Expression<Func<SomeClass, object>> propExpr = y => y.MyString + y.MyString;
> var compExpr = propExpr.Compile();
> var obj = new SomeClass { MyString = "Hello world" };
> compExpr(obj)
Hello worldHello world
> var body = propExpr.Body as BinaryExpression;
> Console.WriteLine(body);
(y.MyString + y.MyString)
> var left = body.Left as MemberExpression;
> Console.WriteLine(left.Member.Name);
MyString
MORE COMPLEX EXPRESSION DEMO

> public class SomeClass { public string MyString { get; set; } }
> Expression<Func<SomeClass, object>> propExpr = y => y.MyString + y.MyString;
> var compExpr = propExpr.Compile();
> var obj = new SomeClass { MyString = "Hello world" };
> compExpr(obj)
Hello worldHello world
> var body = propExpr.Body as BinaryExpression;
Enables us to translate from one domain to another in an ”easy” manner
> Console.WriteLine(body);
(y.MyString + y.MyString)
> var left = body.Left as MemberExpression;
> Console.WriteLine(left.Member.Name);
MyString
Show me the
code!
ELASTICSEARCH CONNECTION

public class ElasticClientWrapper : ElasticClient
{
private static string _connectionString = Settings.ElasticSearchServer;
private static ConnectionSettings _settings =
new ConnectionSettings(new Uri(_connectionString)) //http://demoserver:9200
.SetDefaultIndex(Settings.Alias) //"customer_product_mapping"
.UsePrettyResponses();
public ElasticClientWrapper()
: base(_settings)
{
}
}
//usage
var client = new ElasticClientWrapper();
MAPPING

public class Product
{
public double UnitPrice { get; set; }
public int TotalQuantity { get; set; }
[ElasticProperty(Index = FieldIndexOption.not_analyzed)]
public string ProductName { get; set; }
[ElasticProperty(Index = FieldIndexOption.not_analyzed)]
public string CategoryName { get; set; }
}
public class Customer
{
public string CustomerID { get; set; }
public string CompanyName { get; set; }
public string Address { get; set; }
public string City { get; set; }
public string Country { get; set; }
[ElasticProperty(Type = FieldType.nested)]
public Product[] Products { get; set; }
}
MAPPING & INDEXING

_client = new ElasticClientWrapper();
Mapping created from attributes
_client.CreateIndex("indexName", s =>
s.AddMapping<Customer>(m => m.MapFromAttributes()));

var customers = _customerRepo.GetCustomers();
_client.IndexMany(customers, "indexName");

Indexing will use the mapping
for the specified index
There is async versions of the
methods
ALIAS

_client = new ElasticClientWrapper();
_client.Alias("indexName", "aliasName");

Alias

Index_01
SWAPPING

_client = new ElasticClientWrapper();
_client.Swap("aliasName", new [] { "Index_01" }, new [] { "Index_02" } );

Alias
1.

Index_02

Swap

3.

Index_01

Create new index

2.

Alias

Delete old index
MY QUERY OBJECT (WILL BE USED IN THE EXAMPLES)

public class SearchModel
{
private int? _numberToTake;
public string Query { get; set; }
public Dictionary<string, IEnumerable<string>> Filter { get; set; }
public int? NumberToTake
{
get { return _numberToTake.HasValue ? _numberToTake.Value : 25; }
set { _numberToTake = value; }
}

}
QUERYING

Elasticsearch

NEST

{

_client.Search<Customer>(sd => sd
.QueryString(Input.Query));

"query": {
"query_string": {
"query": "tomas"
}
}
}
FUZZY

Elasticsearch

NEST

{

_client.Search<Customer>(sd => sd
.Query(q => q
.Fuzzy(fd => fd
.OnField("_all")
.MinSimilarity(0.6)
.PrefixLength(1)
.Value(Input.Query))));

"query": {
"fuzzy": {
"_all": {
"min_similarity": 0.6,
"prefix_length": 1,
"value": "tomas"
}
}
}
}

Will enable us to search for both «Thomas» and «Tomas» when writing «Tomas»
FUZZY IMPROVED (USING BOOL QUERY) - ELASTICSEARCH

{
"query": {
"bool": {
"should": [{
"match": {
"_all": {
"query": "tomas"
}
}
},
{
"fuzzy": {
"_all": {
"boost": 0.1,
"min_similarity": 0.6,
"prefix_length": 1,
"value": "tomas"
}
}
}]
}
}
}
FUZZY IMPROVED (USING BOOL QUERY) - NEST

_client.Search<Customer>(sd => sd
.Query(q => q
.Bool(b => b
.Should(new Func<QueryDescriptor<Customer>, BaseQuery>[]
{
_ => _.Match(m => m
.OnField("_all")
.QueryString(Input.Query)),
_ => _.Fuzzy(fd => fd
.OnField("_all")
.MinSimilarity(0.6)
.PrefixLength(1)
.Value(Input.Query)
.Boost(0.1))
}))));
HIGHLIGHT RESULT - ELASTICSEARCH

{
"query": {
// see previous example
},
"highlight": {
"pre_tags": [
"<span class='highlight'>"
],
"post_tags": [
"</span>"
],
"fields": {
"companyName": {
"fragment_size": 100,
"number_of_fragments": 1
}
}
}

}
HIGHLIGHT RESULT - NEST

_client.Search<Customer>(sd => sd
.Query( /* See previous example */ )
.Highlight(h => h
.PreTags("<span class='highlight'>")
.PostTags("</span>")
.OnFields(new Action<HighlightFieldDescriptor<Customer>>[]
{
_ => _
.OnField(c => c.CompanyName)
.NumberOfFragments(1)
.FragmentSize(100)
})));
FACETS - ELASTICSEARCH

{
"query": { /* See previous example */ },
"highlight": { /* See previous example */ },
"facets": {
"products.productName": {
"nested": "products",
"terms": { "field": "products.productName", "size": 1000 }
},
"products.categoryName": {
"nested": "products",
"terms": { "field": "products.categoryName", "size": 1000 }
},
"country": {
"terms": { "field": "country", "size": 1000 }
}
}
}
FACETS - NEST

_client.Search<Customer>(sd => sd
.Query( /* See previous example */ )
.Highlight( /* See previous example */ )
.FacetTerm(f => f
.Nested(c => c.Products)
.OnField(c => c.Products[0].ProductName)
.Size(1000))
.FacetTerm(f => f
.Nested(c => c.Products)
.OnField(c => c.Products[0].CategoryName)
.Size(1000))
.FacetTerm(f => f
.OnField(c => c.Country)
.Size(1000)));
http://go-gaga-over-testing.blogspot.no/2011/09/solution-to-warning-in-quality-center.html
FILTERS - ELASTICSEARCH
{
"query": {
"filtered": {
"query": { /* See previous example */ },
"filter": {
"bool": {
"must": [
{
"terms": { "country": ["usa"] }
},
{
"nested": {
"query": { "terms": { "products.categoryName": ["Condiments", "Seafood"] } },
"path": "products"
}
},
{
"nested": {
"query": { "terms": { "products.productName": ["Chai"] } },
"path": "products"
}
}
]
}
}
}
},
"facets": { /* See previous example */},
"highlight": { /* See previous example */ }
}
FILTERS – NEST – PART 1, THE CUSTOMERS FILTER

private static BaseFilter AddCustomerFilter(IEnumerable<string> items,
Expression<Func<Customer, object>> propExpr)
{
return Filter<Customer>.Terms(propExpr, items.ToArray());
}
FILTERS – NEST – PART 1, THE PRODUCTS FILTER

private static BaseFilter AddProductsFilter(IEnumerable<string> items,
Expression<Func<Customer, object>> propExpr)
{
return Filter<Customer>.Nested(sel => sel
.Path(c => c.Products)
.Query(q => q.Terms(propExpr, items.ToArray())));
}
FILTERS – NEST – PART 1, THE MAGIC DICTIONARY

public Dictionary<string, Func<IEnumerable<string>, BaseFilter>> FilterDesc =
new Dictionary<string, Func<IEnumerable<string>, BaseFilter>>()
{
{"products.productName", ps => AddProductsFilter(ps, c => c
.Products[0].ProductName)},
{"products.categoryName", cs => AddProductsFilter(cs, c => c
.Products[0].CategoryName)},
{"country", cs => AddCustomerFilter(cs, c => c.Country)}
};
FILTERS – NEST – PART 1, ALL THE HELPERS

private static BaseFilter AddCustomerFilter(IEnumerable<string> items,
Expression<Func<Customer, object>> propExpr)
{
return Filter<Customer>.Terms(propExpr, items.ToArray());
}
private static BaseFilter AddProductsFilter(IEnumerable<string> items,
Expression<Func<Customer, object>> propExpr)
{
return Filter<Customer>.Nested(sel => sel
.Path(c => c.Products)
.Query(q => q.Terms(propExpr, items.ToArray())));
}
public Dictionary<string, Func<IEnumerable<string>, BaseFilter>> FilterDesc =
new Dictionary<string, Func<IEnumerable<string>, BaseFilter>>()
{
{"products.productName", ps => AddProductsFilter(ps, c => c
.Products[0].ProductName)},
{"products.categoryName", cs => AddProductsFilter(cs, c => c
.Products[0].CategoryName)},
{"country", cs => AddCustomerFilter(cs, c => c.Country)}
};
FILTERS – NEST – PART 2, THE QUERY
_client.Search<Customer>(sd => sd
.Query(q => q
.Filtered(fq =>
{
fq.Query(qs =>
{
if (!string.IsNullOrEmpty(Input.Query))
{
qs.Bool( /* See previous example */ ));
}
else
{
qs.MatchAll();
}
return qs;
});
if (Input.Filter.Count > 0)
{
var filters =
Input.Filter.Select(_ => FilterDesc[_.Key](_.Value)).ToArray();
fq.Filter(fs => fs.Bool(bf => bf.Must(filters)));
}
}))
.Highlight( /* See previous example */ )
.FacetTerm( /* See previous example */ )
.FacetTerm( /* See previous example */ )
.FacetTerm( /* See previous example */ );
SUMMARY

Elasticsearch

NEST

Easy installation

Strongly typed client

Awesome search engine

Fluent
Abstraction over Elasticsearch
RESOURCES

Demo code: https://github.com/mastoj/NestDemo
Nest documentation: http://nest.azurewebsites.net/
Nest source code: https://github.com/Mpdreamz/NEST
Slideshare: http://www.slideshare.net/mastoj/getting-started-with-elasticsearch-and-net
Sense (great tool to query elastic search in the browser): https://github.com/bleskes/sense
Questions?
Thank you!
@TomasJansson

More Related Content

PPTX
ElasticSearch for .NET Developers
PDF
Solr vs. Elasticsearch, Case by Case: Presented by Alexandre Rafalovitch, UN
KEY
Getting the most out of Java [Nordic Coding-2010]
PDF
Cassandra 3.0 - JSON at scale - StampedeCon 2015
ODP
Terms of endearment - the ElasticSearch Query DSL explained
PDF
Cloudera Impala, updated for v1.0
PPTX
Slick: Bringing Scala’s Powerful Features to Your Database Access
PDF
greenDAO
ElasticSearch for .NET Developers
Solr vs. Elasticsearch, Case by Case: Presented by Alexandre Rafalovitch, UN
Getting the most out of Java [Nordic Coding-2010]
Cassandra 3.0 - JSON at scale - StampedeCon 2015
Terms of endearment - the ElasticSearch Query DSL explained
Cloudera Impala, updated for v1.0
Slick: Bringing Scala’s Powerful Features to Your Database Access
greenDAO

What's hot (20)

PDF
Postgresql search demystified
PDF
MongoDB World 2016: Deciphering .explain() Output
PPTX
Morphia: Simplifying Persistence for Java and MongoDB
PPTX
Webinar: Index Tuning and Evaluation
PPTX
Cassandra 2.2 & 3.0
PDF
Java Persistence Frameworks for MongoDB
PPT
Developing application for Windows Phone 7 in TDD
PDF
concurrency with GPars
PPTX
GreenDao Introduction
PPTX
Simplifying Persistence for Java and MongoDB with Morphia
PDF
Search Evolution - Von Lucene zu Solr und ElasticSearch
PPTX
Solr 6 Feature Preview
PDF
Webinar: MongoDB Persistence with Java and Morphia
PDF
Requery overview
PDF
Indexing and Query Optimizer (Mongo Austin)
PPT
Fast querying indexing for performance (4)
PDF
Green dao
PDF
Learn Ajax here
PDF
[제1회 루씬 한글분석기 기술세미나] solr로 나만의 검색엔진을 만들어보자
PDF
Scala ActiveRecord
Postgresql search demystified
MongoDB World 2016: Deciphering .explain() Output
Morphia: Simplifying Persistence for Java and MongoDB
Webinar: Index Tuning and Evaluation
Cassandra 2.2 & 3.0
Java Persistence Frameworks for MongoDB
Developing application for Windows Phone 7 in TDD
concurrency with GPars
GreenDao Introduction
Simplifying Persistence for Java and MongoDB with Morphia
Search Evolution - Von Lucene zu Solr und ElasticSearch
Solr 6 Feature Preview
Webinar: MongoDB Persistence with Java and Morphia
Requery overview
Indexing and Query Optimizer (Mongo Austin)
Fast querying indexing for performance (4)
Green dao
Learn Ajax here
[제1회 루씬 한글분석기 기술세미나] solr로 나만의 검색엔진을 만들어보자
Scala ActiveRecord
Ad

Viewers also liked (14)

PPTX
Battle of the giants: Apache Solr vs ElasticSearch
PDF
Elasticsearch in 15 minutes
PPT
Elastic search introduction
PDF
Catalogue de stage
PDF
Advancing Earth Science with Elasticsearch at Terradue
PPTX
Scaling Solr with Solr Cloud
PDF
Time Series Processing with Apache Spark
PPTX
Introduction to Elasticsearch with basics of Lucene
PPT
Introduction to Apache Solr.
PDF
Logging with Elasticsearch, Logstash & Kibana
PPT
Boosting Documents in Solr by Recency, Popularity, and User Preferences
PDF
Apache Solr crash course
PPT
Running High Performance and Fault Tolerant Elasticsearch Clusters on Docker
Battle of the giants: Apache Solr vs ElasticSearch
Elasticsearch in 15 minutes
Elastic search introduction
Catalogue de stage
Advancing Earth Science with Elasticsearch at Terradue
Scaling Solr with Solr Cloud
Time Series Processing with Apache Spark
Introduction to Elasticsearch with basics of Lucene
Introduction to Apache Solr.
Logging with Elasticsearch, Logstash & Kibana
Boosting Documents in Solr by Recency, Popularity, and User Preferences
Apache Solr crash course
Running High Performance and Fault Tolerant Elasticsearch Clusters on Docker
Ad

Similar to Getting started with Elasticsearch and .NET (20)

KEY
CouchDB on Android
PDF
How te bring common UI patterns to ADF
PDF
Is writing performant code too expensive?
PPTX
How to Bring Common UI Patterns to ADF
PDF
Windows 8 Training Fundamental - 1
PDF
The Ring programming language version 1.9 book - Part 99 of 210
KEY
Paris js extensions
PDF
Backbone.js — Introduction to client-side JavaScript MVC
PDF
Practica n° 7
PDF
Real-time search in Drupal with Elasticsearch @Moldcamp
PDF
PostgreSQL Open SV 2018
PDF
Elasticsearch in 15 Minutes
PDF
The Ring programming language version 1.7 book - Part 16 of 196
PDF
Angular Schematics
PDF
CouchDB Mobile - From Couch to 5K in 1 Hour
PDF
The Ring programming language version 1.5.2 book - Part 14 of 181
ODP
NYC* 2013 - "Advanced Data Processing: Beyond Queries and Slices"
ODP
Intravert Server side processing for Cassandra
PDF
Cutting Edge Data Processing with PHP & XQuery
KEY
Scala on Your Phone
CouchDB on Android
How te bring common UI patterns to ADF
Is writing performant code too expensive?
How to Bring Common UI Patterns to ADF
Windows 8 Training Fundamental - 1
The Ring programming language version 1.9 book - Part 99 of 210
Paris js extensions
Backbone.js — Introduction to client-side JavaScript MVC
Practica n° 7
Real-time search in Drupal with Elasticsearch @Moldcamp
PostgreSQL Open SV 2018
Elasticsearch in 15 Minutes
The Ring programming language version 1.7 book - Part 16 of 196
Angular Schematics
CouchDB Mobile - From Couch to 5K in 1 Hour
The Ring programming language version 1.5.2 book - Part 14 of 181
NYC* 2013 - "Advanced Data Processing: Beyond Queries and Slices"
Intravert Server side processing for Cassandra
Cutting Edge Data Processing with PHP & XQuery
Scala on Your Phone

More from Tomas Jansson (12)

PPTX
Functional webapplicaations using fsharp and suave
PPTX
F# as our day job by 2016
PPTX
What does the future hold for us in asp.net 5
PPTX
Polyglot heaven
PPTX
OWIN Web API with Linky
PPTX
PPTX
File -> new project to deploy in 10 minutes with TeamCity and Octopus Deploy
PPTX
Deployment taken seriously with Octopus Deploy and TeamCity
PPTX
State or intent
PPTX
NServiceBus workshop presentation
PPTX
SignalR - Building an async web app with .NET
PPTX
REST for .NET - Introduction to ASP.NET Web API
Functional webapplicaations using fsharp and suave
F# as our day job by 2016
What does the future hold for us in asp.net 5
Polyglot heaven
OWIN Web API with Linky
File -> new project to deploy in 10 minutes with TeamCity and Octopus Deploy
Deployment taken seriously with Octopus Deploy and TeamCity
State or intent
NServiceBus workshop presentation
SignalR - Building an async web app with .NET
REST for .NET - Introduction to ASP.NET Web API

Recently uploaded (20)

PDF
“A New Era of 3D Sensing: Transforming Industries and Creating Opportunities,...
PDF
UiPath Agentic Automation session 1: RPA to Agents
PDF
How ambidextrous entrepreneurial leaders react to the artificial intelligence...
PDF
Developing a website for English-speaking practice to English as a foreign la...
PDF
Improvisation in detection of pomegranate leaf disease using transfer learni...
PDF
OpenACC and Open Hackathons Monthly Highlights July 2025
PDF
Zenith AI: Advanced Artificial Intelligence
PPTX
Build Your First AI Agent with UiPath.pptx
PDF
CloudStack 4.21: First Look Webinar slides
PDF
sbt 2.0: go big (Scala Days 2025 edition)
PPT
What is a Computer? Input Devices /output devices
PPT
Module 1.ppt Iot fundamentals and Architecture
PDF
Flame analysis and combustion estimation using large language and vision assi...
PDF
Produktkatalog für HOBO Datenlogger, Wetterstationen, Sensoren, Software und ...
PDF
Statistics on Ai - sourced from AIPRM.pdf
PDF
How IoT Sensor Integration in 2025 is Transforming Industries Worldwide
PPT
Geologic Time for studying geology for geologist
PDF
sustainability-14-14877-v2.pddhzftheheeeee
PDF
STKI Israel Market Study 2025 version august
PDF
Getting started with AI Agents and Multi-Agent Systems
“A New Era of 3D Sensing: Transforming Industries and Creating Opportunities,...
UiPath Agentic Automation session 1: RPA to Agents
How ambidextrous entrepreneurial leaders react to the artificial intelligence...
Developing a website for English-speaking practice to English as a foreign la...
Improvisation in detection of pomegranate leaf disease using transfer learni...
OpenACC and Open Hackathons Monthly Highlights July 2025
Zenith AI: Advanced Artificial Intelligence
Build Your First AI Agent with UiPath.pptx
CloudStack 4.21: First Look Webinar slides
sbt 2.0: go big (Scala Days 2025 edition)
What is a Computer? Input Devices /output devices
Module 1.ppt Iot fundamentals and Architecture
Flame analysis and combustion estimation using large language and vision assi...
Produktkatalog für HOBO Datenlogger, Wetterstationen, Sensoren, Software und ...
Statistics on Ai - sourced from AIPRM.pdf
How IoT Sensor Integration in 2025 is Transforming Industries Worldwide
Geologic Time for studying geology for geologist
sustainability-14-14877-v2.pddhzftheheeeee
STKI Israel Market Study 2025 version august
Getting started with AI Agents and Multi-Agent Systems

Getting started with Elasticsearch and .NET

  • 1. GETTING STARTED WITH ELASTICSEARCH ON WINDOWS AND .NET WITH NEST A short introduction Oslo/NNUG Meetup Tomas Jansson 29/01/2014
  • 2. THIS IS ME Tomas Jansson Manager & Group Lead .NET BEKK Oslo @TomasJansson [email protected] github.com/mastoj blog.tomasjansson.com
  • 7. BACKGROUND This is the data and we need this new application
  • 9. WHAT I WANT TO SHOW YOU IS... Elasticsearch is awesome Indexing using NEST Querying using NEST ... not about advanced elasticsearch hosting
  • 11. INSTALLATION Great news, install as a service added in 0.90.5 Powershell to the rescue
  • 12. NEST Abstraction over Elasticsearch There is an low level abstraction as well called RawElasticClient
  • 15. FUNC DEMO C:Devgit> scriptcs scriptcs (ctrl-c or blank to exit) > Func<int, int, int> add = (x, y) => x + y; > add(1, 3) 4 Func  executable
  • 16. SIMPLE EXPRESSION DEMO > using System.Linq.Expressions; > Expression<Func<int, int, int>> addExpr = (x, y) => x + y; > addExpr(1, 3) Expression  ”function description” (1,1): error CS1955: Non-invocable member 'addExpr' cannot be used like a method. > var binExpr = addExpr.Body as BinaryExpression; > Console.WriteLine(binExpr); (x + y) > var add2 = addExpr.Compile(); > add2(3, 1); 4
  • 17. MORE COMPLEX EXPRESSION DEMO > public class SomeClass { public string MyString { get; set; } } > Expression<Func<SomeClass, object>> propExpr = y => y.MyString + y.MyString; > var compExpr = propExpr.Compile(); > var obj = new SomeClass { MyString = "Hello world" }; > compExpr(obj) Hello worldHello world > var body = propExpr.Body as BinaryExpression; > Console.WriteLine(body); (y.MyString + y.MyString) > var left = body.Left as MemberExpression; > Console.WriteLine(left.Member.Name); MyString
  • 18. MORE COMPLEX EXPRESSION DEMO > public class SomeClass { public string MyString { get; set; } } > Expression<Func<SomeClass, object>> propExpr = y => y.MyString + y.MyString; > var compExpr = propExpr.Compile(); > var obj = new SomeClass { MyString = "Hello world" }; > compExpr(obj) Hello worldHello world > var body = propExpr.Body as BinaryExpression; Enables us to translate from one domain to another in an ”easy” manner > Console.WriteLine(body); (y.MyString + y.MyString) > var left = body.Left as MemberExpression; > Console.WriteLine(left.Member.Name); MyString
  • 20. ELASTICSEARCH CONNECTION public class ElasticClientWrapper : ElasticClient { private static string _connectionString = Settings.ElasticSearchServer; private static ConnectionSettings _settings = new ConnectionSettings(new Uri(_connectionString)) //http://demoserver:9200 .SetDefaultIndex(Settings.Alias) //"customer_product_mapping" .UsePrettyResponses(); public ElasticClientWrapper() : base(_settings) { } } //usage var client = new ElasticClientWrapper();
  • 21. MAPPING public class Product { public double UnitPrice { get; set; } public int TotalQuantity { get; set; } [ElasticProperty(Index = FieldIndexOption.not_analyzed)] public string ProductName { get; set; } [ElasticProperty(Index = FieldIndexOption.not_analyzed)] public string CategoryName { get; set; } } public class Customer { public string CustomerID { get; set; } public string CompanyName { get; set; } public string Address { get; set; } public string City { get; set; } public string Country { get; set; } [ElasticProperty(Type = FieldType.nested)] public Product[] Products { get; set; } }
  • 22. MAPPING & INDEXING _client = new ElasticClientWrapper(); Mapping created from attributes _client.CreateIndex("indexName", s => s.AddMapping<Customer>(m => m.MapFromAttributes())); var customers = _customerRepo.GetCustomers(); _client.IndexMany(customers, "indexName"); Indexing will use the mapping for the specified index There is async versions of the methods
  • 23. ALIAS _client = new ElasticClientWrapper(); _client.Alias("indexName", "aliasName"); Alias Index_01
  • 24. SWAPPING _client = new ElasticClientWrapper(); _client.Swap("aliasName", new [] { "Index_01" }, new [] { "Index_02" } ); Alias 1. Index_02 Swap 3. Index_01 Create new index 2. Alias Delete old index
  • 25. MY QUERY OBJECT (WILL BE USED IN THE EXAMPLES) public class SearchModel { private int? _numberToTake; public string Query { get; set; } public Dictionary<string, IEnumerable<string>> Filter { get; set; } public int? NumberToTake { get { return _numberToTake.HasValue ? _numberToTake.Value : 25; } set { _numberToTake = value; } } }
  • 27. FUZZY Elasticsearch NEST { _client.Search<Customer>(sd => sd .Query(q => q .Fuzzy(fd => fd .OnField("_all") .MinSimilarity(0.6) .PrefixLength(1) .Value(Input.Query)))); "query": { "fuzzy": { "_all": { "min_similarity": 0.6, "prefix_length": 1, "value": "tomas" } } } } Will enable us to search for both «Thomas» and «Tomas» when writing «Tomas»
  • 28. FUZZY IMPROVED (USING BOOL QUERY) - ELASTICSEARCH { "query": { "bool": { "should": [{ "match": { "_all": { "query": "tomas" } } }, { "fuzzy": { "_all": { "boost": 0.1, "min_similarity": 0.6, "prefix_length": 1, "value": "tomas" } } }] } } }
  • 29. FUZZY IMPROVED (USING BOOL QUERY) - NEST _client.Search<Customer>(sd => sd .Query(q => q .Bool(b => b .Should(new Func<QueryDescriptor<Customer>, BaseQuery>[] { _ => _.Match(m => m .OnField("_all") .QueryString(Input.Query)), _ => _.Fuzzy(fd => fd .OnField("_all") .MinSimilarity(0.6) .PrefixLength(1) .Value(Input.Query) .Boost(0.1)) }))));
  • 30. HIGHLIGHT RESULT - ELASTICSEARCH { "query": { // see previous example }, "highlight": { "pre_tags": [ "<span class='highlight'>" ], "post_tags": [ "</span>" ], "fields": { "companyName": { "fragment_size": 100, "number_of_fragments": 1 } } } }
  • 31. HIGHLIGHT RESULT - NEST _client.Search<Customer>(sd => sd .Query( /* See previous example */ ) .Highlight(h => h .PreTags("<span class='highlight'>") .PostTags("</span>") .OnFields(new Action<HighlightFieldDescriptor<Customer>>[] { _ => _ .OnField(c => c.CompanyName) .NumberOfFragments(1) .FragmentSize(100) })));
  • 32. FACETS - ELASTICSEARCH { "query": { /* See previous example */ }, "highlight": { /* See previous example */ }, "facets": { "products.productName": { "nested": "products", "terms": { "field": "products.productName", "size": 1000 } }, "products.categoryName": { "nested": "products", "terms": { "field": "products.categoryName", "size": 1000 } }, "country": { "terms": { "field": "country", "size": 1000 } } } }
  • 33. FACETS - NEST _client.Search<Customer>(sd => sd .Query( /* See previous example */ ) .Highlight( /* See previous example */ ) .FacetTerm(f => f .Nested(c => c.Products) .OnField(c => c.Products[0].ProductName) .Size(1000)) .FacetTerm(f => f .Nested(c => c.Products) .OnField(c => c.Products[0].CategoryName) .Size(1000)) .FacetTerm(f => f .OnField(c => c.Country) .Size(1000)));
  • 35. FILTERS - ELASTICSEARCH { "query": { "filtered": { "query": { /* See previous example */ }, "filter": { "bool": { "must": [ { "terms": { "country": ["usa"] } }, { "nested": { "query": { "terms": { "products.categoryName": ["Condiments", "Seafood"] } }, "path": "products" } }, { "nested": { "query": { "terms": { "products.productName": ["Chai"] } }, "path": "products" } } ] } } } }, "facets": { /* See previous example */}, "highlight": { /* See previous example */ } }
  • 36. FILTERS – NEST – PART 1, THE CUSTOMERS FILTER private static BaseFilter AddCustomerFilter(IEnumerable<string> items, Expression<Func<Customer, object>> propExpr) { return Filter<Customer>.Terms(propExpr, items.ToArray()); }
  • 37. FILTERS – NEST – PART 1, THE PRODUCTS FILTER private static BaseFilter AddProductsFilter(IEnumerable<string> items, Expression<Func<Customer, object>> propExpr) { return Filter<Customer>.Nested(sel => sel .Path(c => c.Products) .Query(q => q.Terms(propExpr, items.ToArray()))); }
  • 38. FILTERS – NEST – PART 1, THE MAGIC DICTIONARY public Dictionary<string, Func<IEnumerable<string>, BaseFilter>> FilterDesc = new Dictionary<string, Func<IEnumerable<string>, BaseFilter>>() { {"products.productName", ps => AddProductsFilter(ps, c => c .Products[0].ProductName)}, {"products.categoryName", cs => AddProductsFilter(cs, c => c .Products[0].CategoryName)}, {"country", cs => AddCustomerFilter(cs, c => c.Country)} };
  • 39. FILTERS – NEST – PART 1, ALL THE HELPERS private static BaseFilter AddCustomerFilter(IEnumerable<string> items, Expression<Func<Customer, object>> propExpr) { return Filter<Customer>.Terms(propExpr, items.ToArray()); } private static BaseFilter AddProductsFilter(IEnumerable<string> items, Expression<Func<Customer, object>> propExpr) { return Filter<Customer>.Nested(sel => sel .Path(c => c.Products) .Query(q => q.Terms(propExpr, items.ToArray()))); } public Dictionary<string, Func<IEnumerable<string>, BaseFilter>> FilterDesc = new Dictionary<string, Func<IEnumerable<string>, BaseFilter>>() { {"products.productName", ps => AddProductsFilter(ps, c => c .Products[0].ProductName)}, {"products.categoryName", cs => AddProductsFilter(cs, c => c .Products[0].CategoryName)}, {"country", cs => AddCustomerFilter(cs, c => c.Country)} };
  • 40. FILTERS – NEST – PART 2, THE QUERY _client.Search<Customer>(sd => sd .Query(q => q .Filtered(fq => { fq.Query(qs => { if (!string.IsNullOrEmpty(Input.Query)) { qs.Bool( /* See previous example */ )); } else { qs.MatchAll(); } return qs; }); if (Input.Filter.Count > 0) { var filters = Input.Filter.Select(_ => FilterDesc[_.Key](_.Value)).ToArray(); fq.Filter(fs => fs.Bool(bf => bf.Must(filters))); } })) .Highlight( /* See previous example */ ) .FacetTerm( /* See previous example */ ) .FacetTerm( /* See previous example */ ) .FacetTerm( /* See previous example */ );
  • 41. SUMMARY Elasticsearch NEST Easy installation Strongly typed client Awesome search engine Fluent Abstraction over Elasticsearch
  • 42. RESOURCES Demo code: https://github.com/mastoj/NestDemo Nest documentation: http://nest.azurewebsites.net/ Nest source code: https://github.com/Mpdreamz/NEST Slideshare: http://www.slideshare.net/mastoj/getting-started-with-elasticsearch-and-net Sense (great tool to query elastic search in the browser): https://github.com/bleskes/sense

Editor's Notes

  • #2: Present thetopic Deployment
  • #3: Trenger en ny profilbilde
  • #4: One of the 108 projects that Karel mentioned
  • #5: C:\Dev\git&gt; scriptcsscriptcs (ctrl-c or blank to exit)&gt; usingSystem.Linq.Expressions;&gt; Func&lt;int, int, int&gt; add = (x, y) =&gt; x + y;&gt; add(1, 3)4&gt; Expression&lt;Func&lt;int, int, int&gt;&gt; addExpr = (x, y) =&gt; x + y;&gt; addExpr(1, 3)(1,1): error CS1955: Non-invocablemember &apos;addExpr&apos; cannot be used like a method.&gt; var body = addExpr.Body as BinaryExpression;&gt; Console.WriteLine(body);(x + y)
  • #6: C:\Dev\git&gt; scriptcsscriptcs (ctrl-c or blank to exit)&gt; usingSystem.Linq.Expressions;&gt; Func&lt;int, int, int&gt; add = (x, y) =&gt; x + y;&gt; add(1, 3)4&gt; Expression&lt;Func&lt;int, int, int&gt;&gt; addExpr = (x, y) =&gt; x + y;&gt; addExpr(1, 3)(1,1): error CS1955: Non-invocablemember &apos;addExpr&apos; cannot be used like a method.&gt; var body = addExpr.Body as BinaryExpression;&gt; Console.WriteLine(body);(x + y)
  • #7: C:\Dev\git&gt; scriptcsscriptcs (ctrl-c or blank to exit)&gt; usingSystem.Linq.Expressions;&gt; Func&lt;int, int, int&gt; add = (x, y) =&gt; x + y;&gt; add(1, 3)4&gt; Expression&lt;Func&lt;int, int, int&gt;&gt; addExpr = (x, y) =&gt; x + y;&gt; addExpr(1, 3)(1,1): error CS1955: Non-invocablemember &apos;addExpr&apos; cannot be used like a method.&gt; var body = addExpr.Body as BinaryExpression;&gt; Console.WriteLine(body);(x + y)
  • #8: C:\Dev\git&gt; scriptcsscriptcs (ctrl-c or blank to exit)&gt; usingSystem.Linq.Expressions;&gt; Func&lt;int, int, int&gt; add = (x, y) =&gt; x + y;&gt; add(1, 3)4&gt; Expression&lt;Func&lt;int, int, int&gt;&gt; addExpr = (x, y) =&gt; x + y;&gt; addExpr(1, 3)(1,1): error CS1955: Non-invocablemember &apos;addExpr&apos; cannot be used like a method.&gt; var body = addExpr.Body as BinaryExpression;&gt; Console.WriteLine(body);(x + y)
  • #9: C:\Dev\git&gt; scriptcsscriptcs (ctrl-c or blank to exit)&gt; usingSystem.Linq.Expressions;&gt; Func&lt;int, int, int&gt; add = (x, y) =&gt; x + y;&gt; add(1, 3)4&gt; Expression&lt;Func&lt;int, int, int&gt;&gt; addExpr = (x, y) =&gt; x + y;&gt; addExpr(1, 3)(1,1): error CS1955: Non-invocablemember &apos;addExpr&apos; cannot be used like a method.&gt; var body = addExpr.Body as BinaryExpression;&gt; Console.WriteLine(body);(x + y)