Dynamic fields
While strongly typed entities are well processed by Linq expressions, some scenarios demand the use of dynamic properties. To support searching in object graphs that cannot have their entire structure be declared upfront, RavenDB exposes the following low-level API for creating fields from within index definitions.
With this feature, you can search for documents even with properties which were created on the fly. For example, consider a Product object that is declared as follows:
public class Product
{
public string Id { get; set; }
public List<Attribute> Attributes { get; set; }
}
public class Attribute
{
public string Name { get; set; }
public string Value { get; set; }
}
This way, properties such as color, size, weight and the like are added only to those products which they are indeed valid properties of. However, while they are easily stored, they cannot be easily searched on.
This is where dynamic fields come in. With the following index definition, RavenDB will index the attribute value under the attribute name in its own field:
public class Product_ByAttribute : AbstractIndexCreationTask<Product>
{
public Product_ByAttribute()
{
Map = products => from p in products
select new
{
_ = p.Attributes
.Select(attribute =>
CreateField(attribute.Name, attribute.Value, false, true))
};
}
}
The underscore used for defining the field name in the Map object is just a convention, you can use any field name instead, but since that we're just want to call the CreateField method and not interesting the field value, we're using _ as a convention to reflect that.
The call to CreateField(...) will generate index fields based on the properties in the provided collection, without creating any field with the name specified there, hence the underscore.
Obviously, this index can have more attributes defined in it for indexing, just like any other ordinary index.
After creating the index, we can easily look for documents using the attribute name as a field to look on, as if it was a real object property. Since it is not really a property, there is no Linq support for it, hence it can only be queried using the LuceneQuery<>() API:
var products = session.Advanced.LuceneQuery<Product>("Product/ByAttribute")
.WhereEquals("Color", "Red")
.ToList();
This will also work for numeric values, so range queries or searches with numeric operators like WhereGreaterThan() will work as well.
The comments section is for user feedback or community content. If you seek assistance or have any questions, please post them at our support forums.
Is it possible to have a dynamic field index use anything other than the default analyzer? For instance, how would I specify that I wanted to use the SimpleAnalyzer for my dynamic field index?
Yes, if you know what the names are. If you don't know the name, you can use an AbstractAnalyzerGenerator to decide what analyzer a dynamic field will use.
Do you have an example of how to use an AbstractAnalyzerGenerator to change the default analyzer for a dynamic field index? There is not much online about this topic. Thanks!
It is pretty simple:
When writing the AbstractAnalyzerGenerator derived class, you can use the provided parameters (index name, the document to be indexed, the query) to decide what analyzer to return.