s.grinovero wrote:
The code itself is looking ok, but you're loosing a lot in flexibility. This is not going to work in master/slave configuration of course, as you shouldn't write to the local index but have to send changes in the form of LuceneWork(s).
Keep in mind that indexwriter.updateDocument() is going to do delete+insert, so we usually prefer to map them that way as some optimizations could be applied; generally speaking Hibernate Search takes care of most optimizations, but in this way you'll have to learn how and apply yourself. Of course LuceneWork only knows about add and delete, so you'll have to map your updates to adds and deletes anyway.
About the point of flexibility, why don't you use a ClassBridge? you can define all fields yourself, like you did with the Map<String,String>, but get away from IO concerns, transaction concerns, and a lot of code.
Another way to map fields to the index without mapping them to the database is to combine the @Transient and @Field annotations on the same getter: inside the getter logic you put the "how to define the value for this unmapped field value", and then still have all declarative features to define how it's going to be indexed. This is IMHO much better as it's also future proof, like in next version you'll be able to use the MassIndexer to rebuild your data, or use the QueryBuilder API, while with your code Hibernate Search can't help you out with nice new features.
Thanks for your reply. I would like to do what you recommend but unfortunately the model that I am working with makes almost impossible to do. Basically we receive an xml message from our client which is magically converted into an object which is persisted however the data I need is stored somewhere completely different and it is impossible to link to the object i am indexing. I have spent a couple of days trying to create a relationship but with no luck.
So if i want to use the master slave configuration I need to do the following:
Code:
FullTextSession fullTextSession = Search.getFullTextSession(sessionFactory.getCurrentSession());
DirectoryProvider[] directoryProviders = fullTextSession.getSearchFactory().getDirectoryProviders(IndexedClass.class);
ReaderProvider readerProvider = fullTextSession.getSearchFactory().getReaderProvider();
IndexReader indexReader = readerProvider.openReader(directoryProviders[0]);
IndexWriter indexWriter = null;
final List<LuceneWork> queue = new ArrayList<LuceneWork>();
try {
Term t = new Term("id", String.valueOf(id));
TermDocs termDocs = indexReader.termDocs(t);
if (termDocs.next()) {
if (IndexWriter.isLocked(directoryProviders[0].getDirectory())) {
IndexWriter.unlock(directoryProviders[0].getDirectory());
}
Document docLoaded = indexReader.document(termDocs.doc());
for(Map.Entry<String, String> entry: values.entrySet()) {
docLoaded.add(new Field(entry.getKey(), entry.getValue(), Field.Store.YES, Field.Index.ANALYZED));
}
LuceneWork deleteWork = new DeleteLuceneWork(id, id.toString(), IndexedClass.class);
LuceneWork addWork = new AddLuceneWork(id, id.toString(), IndexedClass.class, docLoaded);
queue.add(deleteWork);
queue.add(addWork);
jmsTemplate.send(destination, new MessageCreator() {
public Message createMessage(Session session) throws JMSException {
ObjectMessage objectMessage = session.createObjectMessage();
objectMessage.setObject((Serializable)queue);
return objectMessage;
}
});
}
} finally {
readerProvider.closeReader(indexReader);
}
The above would participate in an existing transaction. Is creating a delete and add work item ok?
Any help is extremely appreciated!