Introduction to RavenDB

Post on 18-Dec-2014

670 views 0 download

description

Presentation from SDP 2014 covering RavenDB - the .NET document database. Discussing basic CRUD operations, indexes, and full-text search.

Transcript of Introduction to RavenDB

© Copyright SELA software & Education Labs Ltd. | 14-18 Baruch Hirsch St Bnei Brak, 51202 Israel | www.selagroup.com

SELA DEVELOPER PRACTICEJUNE 29 – JULY 3, 2014

Sasha Goldshtein blog.sashag.netCTO, Sela Group @goldshtn

Introduction to RavenDB

NoSQLThe Zen-like answer: No one can tell you what NoSQL is, they can only tell you what it isn’t

It doesn’t use SQLIt usually is less consistent than RDBMSIt doesn’t put an emphasis on relationsIt emphasizes size and scale over structure

Classes of NoSQL Databases

Document DB

Key-Value

DB

Graph DB

Column DB

RavenDBTransactional document databaseOpen sourcehttps://github.com/ravendb/ravendb with licensing for commercial projectsSchema-less documents, JSON storageRESTful endpointsLINQ-style .NET APIImplicit (usage-based) or explicit indexingPowerful text search based on LuceneReplication and sharding support

Oren Eini(Ayende Rahien)

Hosting RavenDBRaven.Server.exeWindows ServiceIntegrated in IISEmbedded client for stand-alone appsCloud-hosted (e.g. RavenHQ)

Management Studio

Demo

RavenDB Management Studio

Opening a Session

DocumentStore is the session factory; one per application is enoughSupports .NET connection strings or direct initialization:

var ds = new DocumentStore{ Url = "http://localhost:8888"};ds.Initialize();

CRUD Operations on Documentsusing (var session = documentStore.OpenSession()){ session.Store(new Speaker(“Sasha”, “Jerusalem”)); session.SaveChanges();}

using (var session = documentStore.OpenSession()){ Speaker sasha = session.Query<Speaker>() .Where(e => e.City == “Jerusalem”).First(); sasha.City = “Tel-Aviv”; session.SaveChanges();}

Collections and IDsDocuments are stored in JSON formatDocuments have metadata that includes the entity typeA collection is a set of documents with the same entity typeDocuments have unique ids, often a combination of collection name + id

speakers/1conferences/7

Demo

Basic Operations

Modeling Data as Documents

Don’t be tempted to use a document store like a relational database

Documents should be aggregate rootsReferences to other documents are OK but (some) data duplication (denormalization) is also OK

“conference/11” : { tracks: [ { title: “Web”, days: { 1, 2 }, sessions: [ ... ] }, ... ]} Should the tracks

be references?

…But Don’t Go Too Far

Is this a reasonable document?

“blogs/1” : { tags : [ “Windows”, “Visual Studio”, “VSLive” ], posts : [ { title: “Migrating to RavenDB”, content: “When planning a migration to Raven…”, author: “Sasha Goldshtein”, comments: [ ... ] }, ... ]}

My blog has 500 posts

One More Example“orders/1783”: { customer: { name: “James Bond”, id: “customers/007” }, items: [ { product: “Disintegrator”, cost: 78.3, qty: 1 }, { product: “Laser shark”, cost: 99.0, qty: 3 } ]} What if we always

need the customer’s address?

What if the customer’s address changes

often?

What if we always need to know whether

the product is in stock?

Include

Load the referenced document when the referencing document is retrieved

Also supports arrays of referenced documents

Order order = session.Include<Order>(o => o.Customer.Id) .Load(“orders/1783”);Customer customer = session.Load<Customer>( order.Customer.Id);

Order[] orders = session.Query<Order>() .Customize(q => q.Include<Order>(o => o.Customer.Id)) .Where(o => o.Items.Length > 5) .ToArray();

Demo

Include and Load

Indexes

RavenDB automatically creates indexes for you as you run your queries

The indexing happens in the backgroundIndexes can become staleCan wait for non-stale results (if necessary)

RavenQueryStatistics stats;var results = session.Query<Speaker>() .Statistics(out stats) .Where(s => s.Experience > 3) .ToArray();if (stats.IsStale) ...

ACID?If indexes can become stale, does it mean RavenDB is not ACID?

The document store is ACIDThe index store is not

You can insert lots of data very quickly and load it quickly, but indexes take a while to catch up

Indexing FundamentalsA document has fields that are indexed individuallyAn index points from sorted field values to matching documents

"orders/1" : { customer: "Dave", price: 200, items: 3}

"orders/2" : { customer: "Mike", price: 95, items: 1}

"orders/3" : { customer: "Dave", price: 150, items: 2}

Customer

Document IDs

Dave orders/1, orders/3

Mike orders/2PriceRange

Document IDs

0-99 orders/2

100-199 orders/3

200-299 orders/1

Static (Manual) Indexes

Static indexes can provide map and reduce functions to specify what to indexThe simplest form specifies a map function with the fields to index:

ds.DatabaseCommands.PutIndex(“Speaker/ByCity”, new IndexDefinitionBuilder<Speaker> { Map = speakers => from speaker in speakers select new { speaker.City } });

Map/Reduce Index

We often need the speaker count for each of our conferences:

ds.DatabaseCommands.PutIndex(“Conferences/SpeakerCount”, new IndexDefinitionBuilder<Conference, SpeakerCount> { Map = conferences => from conf in conferences from speaker in conf.Speakers select new { Item1 = speaker.Name, Item2 = 1 },

Reduce = results => from result in results group result by result.Item1 into g select new { Item1 = g.Key, Item2 = g.Sum(x => x.Item2) }

});

class SpeakerCount : Tuple<string, int> {}

Using Indexes

In most cases you simply run a query and it will implicitly use or create an indexOr, instruct the query to use your index:

var d = session.Query<SpeakerCount>(“Conferences/SpeakerCount”) .FirstOrDefault(s => s.Item1 == “Dave”);Console.WriteLine(“Dave spoke at {0} conferences”, d.Item2);

var posts = session.Query<Comment>(“CommentsIndex”) .Where(c => c.Author == “Mike”) .OfType<Post>();

Demo

Using Indexes

Full-Text Search Indexes

Made possible by the underlying Lucene.NET engine

public class SpeakerIndex : AbstractIndexCreationTask<Speaker>{ public SpeakerIndex() { Map = speakers => from speaker in speakers select new { speaker.Name }; Index("Name", FieldIndexing.Analyzed); }}

Using Full-Text Search and Query Suggestionsvar query = session.Query<Speaker, SpeakerIndex>() .Where(s => s.Name == name);var speaker = query.FirstOrDefault();

if (speaker == null){ string[] suggestions = query.Suggest().Suggestions;}

Will find “Dave Smith” when searching for “dave” or “smith”

Will suggest “dave” when searching for “david”

Using Lucene Directly

You can also query Lucene directly on any analyzed fieldsE.g., fuzzy search for sessions:

string query = String.Format("Title:{0}*", term);

session.Advanced.LuceneQuery<Session>("SessionIndex") .Where(query) .ToList();

Demo

Full-Text Search and Suggestions

Advanced FeaturesBatch operations by indexAsync API (OpenAsyncSession, await)AttachmentsPatching (partial document updates)Change notifications (IDatabaseChanges)Transactions (TransactionScope)…and many others

http://ravendb.net/docs

Upcoming Features in RavenDB 3.0

Management Studio rewrite in HTML5Web API-based infrastructureFirst-class Java client SDKCustom storage engine (Voron)

© Copyright SELA software & Education Labs Ltd. | 14-18 Baruch Hirsch St Bnei Brak, 51202 Israel | www.selagroup.com

SELA DEVELOPER PRACTICEJUNE 29 – JULY 3, 2014

Thank You!

Sasha Goldshtein@goldshtnblog.sashag.net