Indexes: Indexing Related Documents
To extend indexing capabilities and simplify many scenarios, we have introduced the possibility for indexing related documents.
Example I
Let's consider a simple Product - Category
scenario where you want to look for a Product
by Category Name
.
Without this feature, you would have to create a fairly complex multiple map-reduce index. This is why the LoadDocument
function was introduced.
public static class Products_ByCategoryName extends AbstractIndexCreationTask {
public Products_ByCategoryName() {
map = "docs.Products.Select(product => new { " +
" CategoryName = (this.LoadDocument(product.Category, \"Categories\")).Name " +
"})";
}
}
IndexDefinition indexDefinition = new IndexDefinition();
indexDefinition.setName("Products/ByCategoryName");
indexDefinition.setMaps(Collections.singleton("from product in products " +
" select new " +
" { " +
" CategoryName = LoadDocument(product.Category, \"\"Categories\"\").Name " +
" }"));
store.maintenance().send(new PutIndexesOperation(indexDefinition));
public static class Products_ByCategoryName extends AbstractJavaScriptIndexCreationTask {
public Products_ByCategoryName() {
setMaps(Sets.newHashSet("map('products', function(product ){\n" +
" return {\n" +
" CategoryName : load(product .Category, 'Categories').Name,\n" +
" }\n" +
" })"));
}
}
Now we will be able to search for products using the CategoryName
as a parameter:
List<Product> results = session
.query(Product.class, Products_ByCategoryName.class)
.whereEquals("CategoryName", "Beverages")
.toList();
Example II
Our next scenario will show us how indexing of more complex relationships is also trivial. Let's consider the following case:
public static class Book {
private String id;
private String name;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
public static class Author {
private String id;
private String name;
private List<String> bookIds;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public List<String> getBookIds() {
return bookIds;
}
public void setBookIds(List<String> bookIds) {
this.bookIds = bookIds;
}
}
To create an index with Author Name
and list of Book Names
, we need do the following:
public static class Authors_ByNameAndBooks extends AbstractIndexCreationTask {
public Authors_ByNameAndBooks() {
map = "docs.Authors.Select(author => new { " +
" name = author.name, " +
" books = author.bookIds.Select(x => (this.LoadDocument(x, \"Books\")).name) " +
"})";
}
}
IndexDefinition indexDefinition = new IndexDefinition();
indexDefinition.setName("Authors/ByNameAndBooks");
indexDefinition.setMaps(Collections.singleton("from author in docs.Authors " +
" select new " +
" { " +
" name = author.name, " +
" books = author.bookIds.Select(x => LoadDocument(x, \"\"Books\"\").id) " +
" }"));
store.maintenance().send(new PutIndexesOperation(indexDefinition));
public static class Authors_ByNameAndBookNames extends AbstractJavaScriptIndexCreationTask {
public Authors_ByNameAndBookNames() {
setMaps(Sets.newHashSet("map('author', function(a){\n" +
" return {\n" +
" name: a.name,\n" +
" books: a.booksIds.forEach(x => load(x, 'Book').name)\n" +
" }\n" +
" })"));
}
}
List<Author> results = session
.query(Author.class, Authors_ByNameAndBooks.class)
.whereEquals("name", "Andrzej Sapkowski")
.whereEquals("books", "The Witcher")
.toList();
Remarks
Information
Indexes are updated automatically when related documents change.
Warning
Using the LoadDocument
adds a loaded document to the tracking list. This may cause very expensive calculations to occur, especially when multiple documents are tracking the same document.