Skip to content

Instantly share code, notes, and snippets.

@mattwarren
Created September 13, 2011 16:53
Show Gist options
  • Save mattwarren/1214297 to your computer and use it in GitHub Desktop.
Save mattwarren/1214297 to your computer and use it in GitHub Desktop.
Faceted search SO example
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Linq.Expressions;
using Raven.Abstractions.Data;
using Raven.Abstractions.Indexing;
using Raven.Client;
using Raven.Client.Linq;
namespace Raven.Tests.Faceted
{
public class StackoverflowFacetedIndex : RavenTest
{
private readonly List<Facet> _facets;
public StackoverflowFacetedIndex()
{
_facets = new List<Facet> { new Facet {Name = "Tag"} };
}
public void StackoverflowTest()
{
using (var store = NewDocumentStore())
{
ExecuteTest(store);
}
}
private void ExecuteTest(IDocumentStore store)
{
using (var s = store.OpenSession())
{
s.Store(new FacetSetup { Id = "facets/TagFacets", Facets = _facets });
s.SaveChanges();
store.DatabaseCommands.PutIndex("QuestionTags",
new IndexDefinition
{
Map =
@"from question in docs
from tag in question.Tags
select new
{
question.CreatedOn,
Tag = tag
}"
});
var counter = 0;
var sampleData = GetSampleData();
foreach (var qu in sampleData)
{
s.Store(qu);
counter++;
if (counter % 1024 == 0)
s.SaveChanges();
}
s.SaveChanges();
// Issue a query to make sure the index isn't stale
var result = s.Query<Question>("QuestionTags")
.Customize(x => x.WaitForNonStaleResults())
.ToList();
//WaitForUserToContinueTheTest(store as EmbeddableDocumentStore);
var expressions = new Expression<Func<Question, bool>>[]
{
//Matches all docs
x => x.CreatedOn >= new DateTime(1900, 1, 1),
//Only matches 2 questions (hence tag count should be different)
x => x.CreatedOn >= new DateTime(2008, 5, 7),
//Only matches 1 question
x => x.CreatedOn >= new DateTime(2008, 5, 20),
};
foreach (var exp in expressions)
{
Console.WriteLine("Query: " + exp);
var facetQueryTimer = Stopwatch.StartNew();
var facetResults = s.Query<Question>("QuestionTags")
.Where(exp)
.ToFacets("facets/TagFacets");
facetQueryTimer.Stop();
//Console.WriteLine("Took {0:0.00} msecs", facetQueryTimer.ElapsedMilliseconds);
var filteredData = sampleData
.Where(exp.Compile())
.SelectMany(x => x.Tags)
.GroupBy(tag => tag)
.Select(grp => new { Tag = grp.Key, Count = grp.Count()})
.ToList();
foreach (var tagCount in filteredData)
{
var matchingTag = tagCount.Tag.ToLowerInvariant();
var match = facetResults["Tag"].FirstOrDefault(x => x.Range == matchingTag);
if (match == null || match.Count != tagCount.Count)
{
Console.WriteLine("Tag {0}, expected {1}, got {2}",
tagCount.Tag, tagCount.Count, match == null ? "<null>" : match.Count.ToString());
}
}
var facetList = facetResults["Tag"].Select(x => String.Format("{0} - {1}", x.Range, x.Count));
Console.WriteLine("Results: {0}\n", String.Join(", ", facetList));
}
}
}
private static IEnumerable<Question> GetSampleData()
{
yield return new Question
{
Subject = "Pew Pew",
CreatedOn = new DateTime(2008, 5, 12),
UserId = "Users/Justin",
Tags = new[] {"C#", ".NET", "Regex"}
};
yield return new Question
{
Subject = " RuRoh :( ",
CreatedOn = new DateTime(2008, 5, 3),
UserId = "Users/Ayende",
Tags = new[] {"C#", ".NET"}
};
yield return new Question
{
Subject = "How do I get the codeZ??",
CreatedOn = new DateTime(2008, 5, 20),
UserId = "Users/Matt",
Tags = new[] {"Ruby"}
};
}
}
public class User
{
public string Id { get; set; }
public string DisplayName { get; set; }
}
public class Question
{
public string Id { get; set; }
public string UserId { get; set; } // Reference to User.Id
public string Subject { get; set; }
public DateTime CreatedOn { get; set; } // Utc of course :)
public IList<string> Tags { get; set; } // Tag Id's. (eg. tags/1 tags/2 ...)
}
public class Tag
{
public string Id { get; set; }
public string Name { get; set; }
public IList<string> Aliases { get; set; }
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment