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 static class Result {
private String categoryName;
public String getCategoryName() {
return categoryName;
}
public void setCategoryName(String categoryName) {
this.categoryName = categoryName;
}
}
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));
Now we will be able to search for products using the categoryName
as a parameter:
List<Product> results = session
.query(Products_ByCategoryName.Result.class, Products_ByCategoryName.class)
.whereEquals("CategoryName", "Beverages")
.ofType(Product.class)
.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 static class Result {
private String name;
private List<String> books;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public List<String> getBooks() {
return books;
}
public void setBooks(List<String> books) {
this.books = books;
}
}
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));
List<Author> results = session
.query(Authors_ByNameAndBooks.Result.class, Authors_ByNameAndBooks.class)
.whereEquals("name", "Andrzej Sapkowski")
.whereEquals("books", "The Witcher")
.ofType(Author.class)
.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.