The
LINQ to Lucene project takes its approach from
LINQ to SQL. There is an
Index<T> that provides access to types that are propertly decorated with
Document and
Field attributes and the implement that marker interface
IIndexable using both Standard and Custom Query Operators.
To manage a set of indexes,
LINQ to Lucene has an
IndexSet. Also,
LINQ to SQL data layers can be used as a source for an index set with
DatabaseIndexSet<TDataContext>.
Query operators work on both the string-properties and the class itself if it implements
IIndex. When the left-operand is a property, field-notation syntax is used. When the left-operand is the class itself, the default fields are used (as defined by the
FieldAttribute decorations of the class). The exception to this rule is the
Search method provided only by the class itself, which accepts inline native lucene query syntax. Additional methods for the right operands are
Boost) and
Required.
Type-Conversion occurs using .Net Type-Converters. The property of any type will be converted from the Lucene Index's string type to the appropriate type used by the property as long its type uses a type converter that supports conversion from a string. This automatically includes many .net types including string, int, bool, datetime and more.
Query ReferenceThe table below is based off of the
Lucene Syntax Reference| | Lucene Syntax | LINQ to Lucene |
| Terms & Phrases | "test" or "hello dolly" | c.Match("test") or c.Match("hello dolly") |
| Fields | title:"The Right way" and text:go | c.Title == "The Right way" or c.Text == "go" |
| WildCard | amb?r | c.ContactName.Match("amb?r") |
| Prefix | amber* | c.ContactName.StartsWith("amber") |
| Fuzzy | roam~ or roam~0.8 | c.ContactName.Like("roam") or c.ContactName.Like("roam", 0.8) |
| Proximity | "jakarta apache"~10 | c.ContactName.Like("jakarta apache", 10) |
| Inclusive Range | mod_date:[20020101 TO 20030101] | c.ModifiedDate.Includes("20020101", "20030101") |
| Exclusive Range | title:{Aida TO Carmen} | c.Title.Between("Aida", "Carmen") |
| Boosting | jakarta^4 apache | c.Title.Match("jakarta".Boost(4), apache) |
| Boolean Or | "jakarta apache" OR jakarta | where c.Match("jakarta apache") || c.Match("jakarta") |
| Boolean And | "jakarta apache" AND "Apache Lucene" | where c.Match("jakarta apache") && c.Match("Apache Lucene") |
| Boolean Not | "jakarta apache" NOT "Apache Lucene" | where c.Match("jakarta apache") && !c.Match("Apache Lucene") |
| Required | +jakarta lucene | c.Title.Match("jakarta".Require(), "lucene") |
| Grouping | (jakarta OR apache) AND website | where (c.Title == "jakarta" || c.Title == "apache") && (c.Title == "website") |
| Native Syntax | ie. title:{+return +"pink panther") | c.Search("title:(return +\"pink panther\"") |
Code Samples
Simple Query
// Output: (ContactName:maria)
var query = from c in context.Customers
where c.ContactName == "maria"
select c;
Query with Variables and Projection
// Output: (ContactName:Maria)
string name = "Maria";
var query = from c in context.Customers
where c.ContactName == name
select new { Name=c.ContactName, Id=c.CustomerID, Company=c.CompanyName };
And, Or, Grouping Queries
// Output: ((ContactName:maria) OR (CompanyName:"Ernst Handel"))
var query = from c in context.Customers
where (c.ContactName == "maria") || (c.CompanyName == "Ernst Handel")
select new { Name = c.ContactName, Id = c.CustomerID, Company = c.CompanyName };
// Output: ((ContactName:maria) AND (CompanyName:"Alfreds Futterkiste"))
var query = from c in context.Customers
where (c.ContactName == "maria") && (c.CompanyName == "Alfreds Futterkiste")
select new { Name = c.ContactName, Id = c.CustomerID, Company = c.CompanyName };
// Output: ((ContactName:maria) OR ((ContactName:"Aria Cruz") AND ("Familia Arquibaldo"))
var query = from c in context.Customers
where (c.ContactName == "maria") || (c.ContactName == "Aria Cruz" && c.CompanyName == "Familia Arquibaldo")
select new { Name = c.ContactName, Id = c.CustomerID, Company = c.CompanyName };
Default Field Query
// Output: Folies
var query = from c in context.Customers
where (c.Match("Folies"))
select new { Name = c.ContactName, Id = c.CustomerID, Company = c.CompanyName };
WildCard & Prefix Queries
// Output: (ContactName:ma?ia)
var query = from c in context.Customers
where c.ContactName == "ma?ia"
select new { Name = c.ContactName, Id = c.CustomerID, Company = c.CompanyName };
// Output: ContactName:(mar*)
var query = from c in context.Customers
where c.ContactName.StartsWith("mar")
select new { Name = c.ContactName, Id = c.CustomerID, Company = c.CompanyName };
// Output: ContactName:(Maria And*)
var query = from c in context.Customers
where c.ContactName.StartsWith("Maria And")
select new { Name = c.ContactName, Id = c.CustomerID, Company = c.CompanyName };
Range Queries
// Output: ContactName:{Annette TO Aria}
var query = from c in context.Customers
where c.ContactName.Between("Annette", "Aria")
select new { Name = c.ContactName, Id = c.CustomerID, Company = c.CompanyName };
// Output: ContactName:[Annette TO Aria]
var query = from c in context.Customers
where c.ContactName.Include("Annette", "Aria")
select new { Name = c.ContactName, Id = c.CustomerID, Company = c.CompanyName };
Fuzzy & Proximity Queries
// Output: ContactName:Maria~
var query = from c in context.Customers
where c.ContactName.Like("Maria")
select new { Name = c.ContactName, Id = c.CustomerID, Company = c.CompanyName };
// Output: ContactName:"Maria An"~1
var query = from c in context.Customers
where c.ContactName.Like("Maria An", 1)
select new { Name = c.ContactName, Id = c.CustomerID, Company = c.CompanyName };
Require & Boost Queries
// Output: ContactName:(+maria Anders)
var query = from c in context.Customers
where c.ContactName.Match("maria".Require(), "Anders")
select new { Name = c.ContactName, Id = c.CustomerID, Company = c.CompanyName };
// Output: ContactName:(maria^3 Art)
var query = from c in context.Customers
where c.ContactName.Match("maria".Boost(3), "Art")
select new { Name = c.ContactName, Id = c.CustomerID, Company = c.CompanyName };
Native Syntax Query
// Output: ((+la^4 OR en) OR (WeirdCustomName:mar* AND !CompanyName:Victuailles))
var query = from c in context.Customers
where c.Search("((+la^4 OR en) OR (WeirdCustomName:mar* AND !CompanyName:Victuailles))")
select new { Name = c.ContactName, Id = c.CustomerID, Company = c.CompanyName };
CreditThe Wayward WeblogAgain, credit must be given to Matt Warren of the Wayward Weblog who provided the building blocks used by
LINQ to Lucene with regards to the Expression Tree Evaluation and projection. For a deeper understanding of how this project was implemented, it is reccomended that you spend time with the LINQ series he provides. Thank you Matt.