SlideShare a Scribd company logo
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

What's hot (20)

Postgresql search demystified
Postgresql search demystified
javier ramirez
 
MongoDB World 2016: Deciphering .explain() Output
MongoDB World 2016: Deciphering .explain() Output
MongoDB
 
Morphia: Simplifying Persistence for Java and MongoDB
Morphia: Simplifying Persistence for Java and MongoDB
Jeff Yemin
 
Webinar: Index Tuning and Evaluation
Webinar: Index Tuning and Evaluation
MongoDB
 
Cassandra 2.2 & 3.0
Cassandra 2.2 & 3.0
Victor Coustenoble
 
Java Persistence Frameworks for MongoDB
Java Persistence Frameworks for MongoDB
MongoDB
 
Developing application for Windows Phone 7 in TDD
Developing application for Windows Phone 7 in TDD
Michele Capra
 
concurrency with GPars
concurrency with GPars
Paul King
 
GreenDao Introduction
GreenDao Introduction
Booch Lin
 
Simplifying Persistence for Java and MongoDB with Morphia
Simplifying Persistence for Java and MongoDB with Morphia
MongoDB
 
Search Evolution - Von Lucene zu Solr und ElasticSearch
Search Evolution - Von Lucene zu Solr und ElasticSearch
Florian Hopf
 
Solr 6 Feature Preview
Solr 6 Feature Preview
Yonik Seeley
 
Webinar: MongoDB Persistence with Java and Morphia
Webinar: MongoDB Persistence with Java and Morphia
MongoDB
 
Requery overview
Requery overview
Sunghyouk Bae
 
Indexing and Query Optimizer (Mongo Austin)
Indexing and Query Optimizer (Mongo Austin)
MongoDB
 
Fast querying indexing for performance (4)
Fast querying indexing for performance (4)
MongoDB
 
Green dao
Green dao
彥彬 洪
 
Learn Ajax here
Learn Ajax here
jarnail
 
[제1회 루씬 한글분석기 기술세미나] solr로 나만의 검색엔진을 만들어보자
[제1회 루씬 한글분석기 기술세미나] solr로 나만의 검색엔진을 만들어보자
Donghyeok Kang
 
Scala ActiveRecord
Scala ActiveRecord
scalaconfjp
 
Postgresql search demystified
Postgresql search demystified
javier ramirez
 
MongoDB World 2016: Deciphering .explain() Output
MongoDB World 2016: Deciphering .explain() Output
MongoDB
 
Morphia: Simplifying Persistence for Java and MongoDB
Morphia: Simplifying Persistence for Java and MongoDB
Jeff Yemin
 
Webinar: Index Tuning and Evaluation
Webinar: Index Tuning and Evaluation
MongoDB
 
Java Persistence Frameworks for MongoDB
Java Persistence Frameworks for MongoDB
MongoDB
 
Developing application for Windows Phone 7 in TDD
Developing application for Windows Phone 7 in TDD
Michele Capra
 
concurrency with GPars
concurrency with GPars
Paul King
 
GreenDao Introduction
GreenDao Introduction
Booch Lin
 
Simplifying Persistence for Java and MongoDB with Morphia
Simplifying Persistence for Java and MongoDB with Morphia
MongoDB
 
Search Evolution - Von Lucene zu Solr und ElasticSearch
Search Evolution - Von Lucene zu Solr und ElasticSearch
Florian Hopf
 
Solr 6 Feature Preview
Solr 6 Feature Preview
Yonik Seeley
 
Webinar: MongoDB Persistence with Java and Morphia
Webinar: MongoDB Persistence with Java and Morphia
MongoDB
 
Indexing and Query Optimizer (Mongo Austin)
Indexing and Query Optimizer (Mongo Austin)
MongoDB
 
Fast querying indexing for performance (4)
Fast querying indexing for performance (4)
MongoDB
 
Learn Ajax here
Learn Ajax here
jarnail
 
[제1회 루씬 한글분석기 기술세미나] solr로 나만의 검색엔진을 만들어보자
[제1회 루씬 한글분석기 기술세미나] solr로 나만의 검색엔진을 만들어보자
Donghyeok Kang
 
Scala ActiveRecord
Scala ActiveRecord
scalaconfjp
 

Viewers also liked (14)

Battle of the giants: Apache Solr vs ElasticSearch
Battle of the giants: Apache Solr vs ElasticSearch
Rafał Kuć
 
Elasticsearch in 15 minutes
Elasticsearch in 15 minutes
David Pilato
 
Elastic search introduction
Elastic search introduction
Jackson dos Santos Olveira
 
Catalogue de stage
Catalogue de stage
mzoughi Anis
 
Advancing Earth Science with Elasticsearch at Terradue
Advancing Earth Science with Elasticsearch at Terradue
terradue
 
Scaling Solr with Solr Cloud
Scaling Solr with Solr Cloud
Sematext Group, Inc.
 
Time Series Processing with Apache Spark
Time Series Processing with Apache Spark
QAware GmbH
 
Introduction to Elasticsearch with basics of Lucene
Introduction to Elasticsearch with basics of Lucene
Rahul Jain
 
Introduction to Apache Solr.
Introduction to Apache Solr.
ashish0x90
 
Logging with Elasticsearch, Logstash & Kibana
Logging with Elasticsearch, Logstash & Kibana
Amazee Labs
 
Boosting Documents in Solr by Recency, Popularity, and User Preferences
Boosting Documents in Solr by Recency, Popularity, and User Preferences
Lucidworks (Archived)
 
Design Patterns
Design Patterns
Betclic Everest Group Tech Team
 
Apache Solr crash course
Apache Solr crash course
Tommaso Teofili
 
Running High Performance and Fault Tolerant Elasticsearch Clusters on Docker
Running High Performance and Fault Tolerant Elasticsearch Clusters on Docker
Sematext Group, Inc.
 
Battle of the giants: Apache Solr vs ElasticSearch
Battle of the giants: Apache Solr vs ElasticSearch
Rafał Kuć
 
Elasticsearch in 15 minutes
Elasticsearch in 15 minutes
David Pilato
 
Catalogue de stage
Catalogue de stage
mzoughi Anis
 
Advancing Earth Science with Elasticsearch at Terradue
Advancing Earth Science with Elasticsearch at Terradue
terradue
 
Time Series Processing with Apache Spark
Time Series Processing with Apache Spark
QAware GmbH
 
Introduction to Elasticsearch with basics of Lucene
Introduction to Elasticsearch with basics of Lucene
Rahul Jain
 
Introduction to Apache Solr.
Introduction to Apache Solr.
ashish0x90
 
Logging with Elasticsearch, Logstash & Kibana
Logging with Elasticsearch, Logstash & Kibana
Amazee Labs
 
Boosting Documents in Solr by Recency, Popularity, and User Preferences
Boosting Documents in Solr by Recency, Popularity, and User Preferences
Lucidworks (Archived)
 
Apache Solr crash course
Apache Solr crash course
Tommaso Teofili
 
Running High Performance and Fault Tolerant Elasticsearch Clusters on Docker
Running High Performance and Fault Tolerant Elasticsearch Clusters on Docker
Sematext Group, Inc.
 
Ad

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

CouchDB on Android
CouchDB on Android
Sven Haiges
 
How te bring common UI patterns to ADF
How te bring common UI patterns to ADF
Getting value from IoT, Integration and Data Analytics
 
Is writing performant code too expensive?
Is writing performant code too expensive?
Tomasz Kowalczewski
 
How to Bring Common UI Patterns to ADF
How to Bring Common UI Patterns to ADF
Luc Bors
 
Windows 8 Training Fundamental - 1
Windows 8 Training Fundamental - 1
Kevin Octavian
 
The Ring programming language version 1.9 book - Part 99 of 210
The Ring programming language version 1.9 book - Part 99 of 210
Mahmoud Samir Fayed
 
Paris js extensions
Paris js extensions
erwanl
 
Backbone.js — Introduction to client-side JavaScript MVC
Backbone.js — Introduction to client-side JavaScript MVC
pootsbook
 
Practica n° 7
Practica n° 7
rafobarrientos
 
Real-time search in Drupal with Elasticsearch @Moldcamp
Real-time search in Drupal with Elasticsearch @Moldcamp
Alexei Gorobets
 
PostgreSQL Open SV 2018
PostgreSQL Open SV 2018
artgillespie
 
Elasticsearch in 15 Minutes
Elasticsearch in 15 Minutes
Karel Minarik
 
The Ring programming language version 1.7 book - Part 16 of 196
The Ring programming language version 1.7 book - Part 16 of 196
Mahmoud Samir Fayed
 
Angular Schematics
Angular Schematics
Christoffer Noring
 
CouchDB Mobile - From Couch to 5K in 1 Hour
CouchDB Mobile - From Couch to 5K in 1 Hour
Peter Friese
 
The Ring programming language version 1.5.2 book - Part 14 of 181
The Ring programming language version 1.5.2 book - Part 14 of 181
Mahmoud Samir Fayed
 
NYC* 2013 - "Advanced Data Processing: Beyond Queries and Slices"
NYC* 2013 - "Advanced Data Processing: Beyond Queries and Slices"
DataStax Academy
 
Intravert Server side processing for Cassandra
Intravert Server side processing for Cassandra
Edward Capriolo
 
Cutting Edge Data Processing with PHP & XQuery
Cutting Edge Data Processing with PHP & XQuery
William Candillon
 
Scala on Your Phone
Scala on Your Phone
Michael Galpin
 
CouchDB on Android
CouchDB on Android
Sven Haiges
 
Is writing performant code too expensive?
Is writing performant code too expensive?
Tomasz Kowalczewski
 
How to Bring Common UI Patterns to ADF
How to Bring Common UI Patterns to ADF
Luc Bors
 
Windows 8 Training Fundamental - 1
Windows 8 Training Fundamental - 1
Kevin Octavian
 
The Ring programming language version 1.9 book - Part 99 of 210
The Ring programming language version 1.9 book - Part 99 of 210
Mahmoud Samir Fayed
 
Paris js extensions
Paris js extensions
erwanl
 
Backbone.js — Introduction to client-side JavaScript MVC
Backbone.js — Introduction to client-side JavaScript MVC
pootsbook
 
Real-time search in Drupal with Elasticsearch @Moldcamp
Real-time search in Drupal with Elasticsearch @Moldcamp
Alexei Gorobets
 
PostgreSQL Open SV 2018
PostgreSQL Open SV 2018
artgillespie
 
Elasticsearch in 15 Minutes
Elasticsearch in 15 Minutes
Karel Minarik
 
The Ring programming language version 1.7 book - Part 16 of 196
The Ring programming language version 1.7 book - Part 16 of 196
Mahmoud Samir Fayed
 
CouchDB Mobile - From Couch to 5K in 1 Hour
CouchDB Mobile - From Couch to 5K in 1 Hour
Peter Friese
 
The Ring programming language version 1.5.2 book - Part 14 of 181
The Ring programming language version 1.5.2 book - Part 14 of 181
Mahmoud Samir Fayed
 
NYC* 2013 - "Advanced Data Processing: Beyond Queries and Slices"
NYC* 2013 - "Advanced Data Processing: Beyond Queries and Slices"
DataStax Academy
 
Intravert Server side processing for Cassandra
Intravert Server side processing for Cassandra
Edward Capriolo
 
Cutting Edge Data Processing with PHP & XQuery
Cutting Edge Data Processing with PHP & XQuery
William Candillon
 
Ad

More from Tomas Jansson (12)

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

Recently uploaded (20)

MuleSoft for AgentForce : Topic Center and API Catalog
MuleSoft for AgentForce : Topic Center and API Catalog
shyamraj55
 
Can We Use Rust to Develop Extensions for PostgreSQL? (POSETTE: An Event for ...
Can We Use Rust to Develop Extensions for PostgreSQL? (POSETTE: An Event for ...
NTT DATA Technology & Innovation
 
The State of Web3 Industry- Industry Report
The State of Web3 Industry- Industry Report
Liveplex
 
Analysis of the changes in the attitude of the news comments caused by knowin...
Analysis of the changes in the attitude of the news comments caused by knowin...
Matsushita Laboratory
 
FIDO Seminar: Targeting Trust: The Future of Identity in the Workforce.pptx
FIDO Seminar: Targeting Trust: The Future of Identity in the Workforce.pptx
FIDO Alliance
 
Agentic AI: Beyond the Buzz- LangGraph Studio V2
Agentic AI: Beyond the Buzz- LangGraph Studio V2
Shashikant Jagtap
 
Murdledescargadarkweb.pdfvolumen1 100 elementary
Murdledescargadarkweb.pdfvolumen1 100 elementary
JorgeSemperteguiMont
 
Kubernetes Security Act Now Before It’s Too Late
Kubernetes Security Act Now Before It’s Too Late
Michael Furman
 
“Why It’s Critical to Have an Integrated Development Methodology for Edge AI,...
“Why It’s Critical to Have an Integrated Development Methodology for Edge AI,...
Edge AI and Vision Alliance
 
Scaling GenAI Inference From Prototype to Production: Real-World Lessons in S...
Scaling GenAI Inference From Prototype to Production: Real-World Lessons in S...
Anish Kumar
 
FME for Distribution & Transmission Integrity Management Program (DIMP & TIMP)
FME for Distribution & Transmission Integrity Management Program (DIMP & TIMP)
Safe Software
 
FIDO Alliance Seminar State of Passkeys.pptx
FIDO Alliance Seminar State of Passkeys.pptx
FIDO Alliance
 
Your startup on AWS - How to architect and maintain a Lean and Mean account J...
Your startup on AWS - How to architect and maintain a Lean and Mean account J...
angelo60207
 
Providing an OGC API Processes REST Interface for FME Flow
Providing an OGC API Processes REST Interface for FME Flow
Safe Software
 
High Availability On-Premises FME Flow.pdf
High Availability On-Premises FME Flow.pdf
Safe Software
 
Mastering AI Workflows with FME - Peak of Data & AI 2025
Mastering AI Workflows with FME - Peak of Data & AI 2025
Safe Software
 
Oracle Cloud Infrastructure Generative AI Professional
Oracle Cloud Infrastructure Generative AI Professional
VICTOR MAESTRE RAMIREZ
 
No-Code Workflows for CAD & 3D Data: Scaling AI-Driven Infrastructure
No-Code Workflows for CAD & 3D Data: Scaling AI-Driven Infrastructure
Safe Software
 
Supporting the NextGen 911 Digital Transformation with FME
Supporting the NextGen 911 Digital Transformation with FME
Safe Software
 
cnc-drilling-dowel-inserting-machine-drillteq-d-510-english.pdf
cnc-drilling-dowel-inserting-machine-drillteq-d-510-english.pdf
AmirStern2
 
MuleSoft for AgentForce : Topic Center and API Catalog
MuleSoft for AgentForce : Topic Center and API Catalog
shyamraj55
 
Can We Use Rust to Develop Extensions for PostgreSQL? (POSETTE: An Event for ...
Can We Use Rust to Develop Extensions for PostgreSQL? (POSETTE: An Event for ...
NTT DATA Technology & Innovation
 
The State of Web3 Industry- Industry Report
The State of Web3 Industry- Industry Report
Liveplex
 
Analysis of the changes in the attitude of the news comments caused by knowin...
Analysis of the changes in the attitude of the news comments caused by knowin...
Matsushita Laboratory
 
FIDO Seminar: Targeting Trust: The Future of Identity in the Workforce.pptx
FIDO Seminar: Targeting Trust: The Future of Identity in the Workforce.pptx
FIDO Alliance
 
Agentic AI: Beyond the Buzz- LangGraph Studio V2
Agentic AI: Beyond the Buzz- LangGraph Studio V2
Shashikant Jagtap
 
Murdledescargadarkweb.pdfvolumen1 100 elementary
Murdledescargadarkweb.pdfvolumen1 100 elementary
JorgeSemperteguiMont
 
Kubernetes Security Act Now Before It’s Too Late
Kubernetes Security Act Now Before It’s Too Late
Michael Furman
 
“Why It’s Critical to Have an Integrated Development Methodology for Edge AI,...
“Why It’s Critical to Have an Integrated Development Methodology for Edge AI,...
Edge AI and Vision Alliance
 
Scaling GenAI Inference From Prototype to Production: Real-World Lessons in S...
Scaling GenAI Inference From Prototype to Production: Real-World Lessons in S...
Anish Kumar
 
FME for Distribution & Transmission Integrity Management Program (DIMP & TIMP)
FME for Distribution & Transmission Integrity Management Program (DIMP & TIMP)
Safe Software
 
FIDO Alliance Seminar State of Passkeys.pptx
FIDO Alliance Seminar State of Passkeys.pptx
FIDO Alliance
 
Your startup on AWS - How to architect and maintain a Lean and Mean account J...
Your startup on AWS - How to architect and maintain a Lean and Mean account J...
angelo60207
 
Providing an OGC API Processes REST Interface for FME Flow
Providing an OGC API Processes REST Interface for FME Flow
Safe Software
 
High Availability On-Premises FME Flow.pdf
High Availability On-Premises FME Flow.pdf
Safe Software
 
Mastering AI Workflows with FME - Peak of Data & AI 2025
Mastering AI Workflows with FME - Peak of Data & AI 2025
Safe Software
 
Oracle Cloud Infrastructure Generative AI Professional
Oracle Cloud Infrastructure Generative AI Professional
VICTOR MAESTRE RAMIREZ
 
No-Code Workflows for CAD & 3D Data: Scaling AI-Driven Infrastructure
No-Code Workflows for CAD & 3D Data: Scaling AI-Driven Infrastructure
Safe Software
 
Supporting the NextGen 911 Digital Transformation with FME
Supporting the NextGen 911 Digital Transformation with FME
Safe Software
 
cnc-drilling-dowel-inserting-machine-drillteq-d-510-english.pdf
cnc-drilling-dowel-inserting-machine-drillteq-d-510-english.pdf
AmirStern2
 

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)