Hibernate Search - Reindex when associated object is updated - hibernate-search

I am using Hibernate Search. I have two classes Article and Publisher.
public class Publisher {
private String name;
}
public class Article {
private Publisher publisher;
private String title;
private String description;
}
I want to create an index for a merged field that contains all fields in Article class and name field in Publisher class.
A requirement is that when publisher name is changed and persisted to the database, all the articles from that publisher would need to be re-indexed as well. How do I accomplish this? Many thanks!!!

You would use #IndexedEmbedded and #ContainedIn. The former on publisher in Article and the latter on articles in Publisher. At the moment you don't have articles field in Publisher, but to make this work you need a bidirectional link.

Related

Avoid multiple transactions within single execution when updating entities in MongoDB

I am working with 2 MongoDB collections, Recipe, and Menu. A single Menu is a combination of Recipe. Refer the below code segment for more information
#Document
public class Recipe {
private String id;
private String name;
private String description;
// getter and setter
}
#Document
public class Menu {
private String id;
private String name;
private List<RecipeItem> recipeItem;
// getter and setter
}
public class RecipeItem {
private String id;
private String name;
private String description;
// getter and setter
}
RecipeItem is just a copy of the Recipe object which is referred within the Menu collection
When the Menu collection is saved, you can add recipes to the menu and therefore a list of Recipe objects will also be saved within the Menu collection in the name of RecipeItem. When any of the Recipe is updated, the corresponding RecipeItem which is in the Menu is also required to be updated. Otherwise, the recipe within the Menu becomes outdated compared to the current Recipe after updating. So I have to iterate Menu collection which contains the updated Recipe by Id and needs to update the recipe information within the Menu collection.
So the update Menu function will initiate multiple transactions within the single execution and therefore we are in a need of a rollback mechanism as well. So I am not very fond of this approach.
I am new to MongoDB and I want to verify whether the current database design of Menu and Recipe is correct or incorrect? If yes what will be the optimal way of doing it? I know that use a DB ref between collections can be used, but there is a performance impact on it.
The Menu document should store a list of Recipe s IDs rather than the recipes themselves. Then you can dispense with RecipeItem and use Recipe directly.
It would seem more sensible that a Recipe consists of RecipeItems (Apple tart consists of flour, sugar, eggs, apples etc.).
In any case a reference would remove the need to keep two lists in sync.

Spring Mongo DB #DBRef(lazy=true) - How to lazy Load

I have a model like the one below (assume as pseudo code )
class Student {
#Id
private String id;
private String firstname;
.....;
#DBRef(lazy=true)
private College college
// getters and setters
}
class College {
#Id
private String id;
private String name;
// other attributes.
// getters and setters
}
I am using #DBRef(lazy=true) so that I do not load the college associated with the student. For example: if I have a repository method for Student called findByFirstname(String firstname), I can load the student without the college.
However, at times I would also want to load the student with college. Is it possible to write a repository method with a custom query using the #Query annotation (org.springframework.data.mongodb.core.query.Query) where I can load the student (all fields) and also the associated college instance ?
#Query( what should go here ?)
Student findStudentWithCollege(String firstname)
If no, then what would be a suggested way to load lazy documents on demand ?
As per the documentation
"DBRefs can also be resolved lazily. In this case the actual Object or Collection of references is resolved on first access of the property. Use the lazy attribute of #DBRef to specify this. Required properties that are also defined as lazy loading DBRef and used as constructor arguments are also decorated with the lazy loading proxy making sure to put as little pressure on the database and network as possible." I guess this may not be suitable for cases where one would want to load a student whose last name is "Smith" along with the college instance for each of the students retrieved.

Possible to ignore #TextIndexed on fields with Spring Data MongoDB?

I have class along the lines of:
public class Person {
#TextIndexed
String name;
List<Person> contacts;
// getters and setters
...
}
The #TextIndexed allows me to search people by name. However, after I recently added a list of contacts I discovered that their names will also be added to the text index. Is there a way around this other than having a separate class - identical to Person but without the #TextIndexed annotations? Perhaps an annotation that will serialize the field but not utilize its indexes?
I am not aware of such an annotation, but one possible way to go about this would be to use polymorphism. For example, an abstract Person class that is extended by both versions (indexed and non-indexed). Then only annotate the name attribute inside the class where you want it indexed.

How to properly use Locking or Transactions to prevent duplicates using Spring Data

What is the best way to check if a record exists and if it doesn't, create it (avoiding duplicates)?
Keep in mind that this is a distributed application running across many application servers.
I'm trying to avoid these:
Race Conditions
TOCTOU
A simple example:
Person.java
#Entity
public class Person {
#Id
#GeneratedValue
private long id;
private String firstName;
private String lastName;
//Getters and Setters Omitted
}
PersonRepository.java
public interface PersonRepository extends CrudRepository<Person, Long>{
public Person findByFirstName(String firstName);
}
Some Method
public void someMethod() {
Person john = new Person();
john.setFirstName("John");
john.setLastName("Doe");
if(personRepo.findByFirstName(john.getFirstName()) == null){
personRepo.save(john);
}else{
//Don't Save Person
}
}
Clearly as the code currently stands, there is a chance that the Person could be inserted in the database in between the time I checked if it already exists and when I insert it myself. Thus a duplicate would be created.
How should I avoid this?
Based on my initial research, perhaps a combination of
#Transactional
#Lock
But the exact configuration is what I'm unsure of. Any guidance would be greatly appreciated. To reiterate, this application will be distributed across multiple servers so this must still work in a highly-available, distributed environment.
For Inserts: if you want to prevent same recordsto be persisted, than you may want to take some precoutions on DB side. In your example, if firstname should be unique, then define a unique index on that column, or a agroup of colunsd that should be unique, and let the DB handle the check, you just insert & get exception if you're inserting a record that's already inserted.
For updates: use #Version (javax.persistence.Version) annotation like this:
#Version
private long version;
Define a version column in tables, Hibernate or any other ORM will automatically populate the value & also verison to where clause when entity updated. So if someone try to update the old entity, it prevent this. Be careful, this doesn't throw exception, just return update count as 0, so you may want to check this.

Hazelcast Complex Object Model in Cache

I am looking to put a complex model into Hazelcast to use it as the data tier of an application with MapStore implementations rendering the actual objects to the database. So for example, lets say we have the following noxiously common model where I have stripped out getters and setters for brevity:
class Customer {
public int id;
public String name;
public Address address;
}
class Address {
public int id;
public String street;
public string city;
public String state;
public String zip;
}
class InterestGroup {
public int id;
public String name;
public List<Customer> customers;
}
This is a model that I want to store in the database but I also want to map into Hazelcast. Furthermore lets say that I want customers to share addresses such that if the address changes for one, it will change for all customers with that address.
I can write MapStore classes to read this information out of the database and even give each object a primary key to use as a map key. What I am having trouble with is setting up navigation within the map between entities. Lets say I obtain a customer and want to navigate to the address of that customer and then get all customers that use that address.
If I load customers and addresses into a map, I dont want to embed all customers in an address nor do I want to embed the address in each customer. I want to navigate transparrently from the customer to the address. Is there a means by which I could do this in hazelcast without breaking the dynamics of a nested object but while allowing addresses to live in another map? The situation is similar for interest groups. If I embed all customers in an interest group then I am duplicating data all over especially if the customer is in several interest groups.
To accomplish this without duplication all over do I have to compromise the object structure of my entities?
Thanks in advance.
If you know how to build the address_key for the address Hazelcast map you can implement HazecastInstanceAware to your model classes and build some kind of "lazy fetch" using getters to retrieve the address. Does that make sense to you? :)