Search with Lucene in Playframework 1.x
Since the project in Java - it was very tempting to use Lucene for this.
In Google, I immediately found a wonderful module for the Playframework called Search , I also found the Elastic Search module , which also uses Lucene, but it requires the installation of a separate server, and therefore was flagged. I liked the Search module because of its simplicity - all the “bells and whistles” in it are encapsulated, so it’s very easy to use.
With the installation of the module, as always in Play-e, there were no problems, the teamplay install search worked with a bang and deflated the module from the repository.
By adding module.search = $ {play.path} /modules/search-2.0 in application.conf, I could already use it in the application.
Following the short tutorial, I added to the Entry entity , which actually should have searched, the @Indexed annotation , and the description field the @Field annotation .
By writing the following code in the controller:
public static void search(String phrase, int page) {
int pageSize = PAGE_SIZE;
Query query = Search.search("description:" + phrase, Entry.class);
List entries = query.page(page*pageSize, pageSize).fetch();
long totalCount = query.count();
render(entries, totalCount, page, pageSize, phrase);
}
I was already ready to do the first tests and increase the functionality, but problems started here ... The
search did not work, that is, the count () method returned 0 , and the entries list was empty. I tried to search in both Russian and English, and called Search.rebuildAllIndexes () , and tried a lot more, but the result was unchanged.
Fortunately, the module in play-e is downloaded along with the source and could be biased. A short debug showed that the description field is not put in the index . I climbed a little deeper and saw that in search of the @Field annotation the entity field uses the object.getClass () method . getFields (), but stop, this method returns only public fields, and in my essence, the fields, as expected, have protected access, and the author of the module should use the getDeclaredFields () method .
Here I will make a digression: I absolutely did not want to reassemble the module and change the code in it, at least because I would lose the ability to do play install search on a "combat" server, but I would have to put my hands on the reassembled module. Writing a bug report or offering a patch was not a quick undertaking, but the functionality was needed now.
In general, it was decided to make the description field public, and write todo until this bug was fixed in the module. And, lo and behold, the search has earned!
The next problem, which I already guessed after reading the tutorial, was that the module had a “killer feature” - automatic updating of the index (and adding new records) during CRUD operations with the entity — I did not need this. The fact is that the records that are added to the system first go through pre-moderation, and I absolutely do not need the “un-moderated” records to get into the search.
I want to call Search.index (entry) myself after moderation. I really hoped that I would find in the sources a check for some line in the config: do the index automatically update or not, but I came across this in the SearchPlugin code:
@Override
public void onEvent(String message, Object context) {
if (!message.startsWith("JPASupport"))
return;
if (message.equals("JPASupport.objectPersisted") || message.equals("JPASupport.objectUpdated")) {
Search.index (context);
} else if (message.equals("JPASupport.objectDeleted")) {
Search.unIndex(context);
}
}
You couldn’t turn it off in any way, and it seems like it’s time to think about sending a patch and kicking so that a version with a fix is released faster, but a brilliant idea was born: after all, in essence, it will still be a module or just a set of libraries, which I put in the lib folder.
Digging in the code showed that when you start the application you need to do:
Search.init();
FileExtractor.init();
And when you stop:
try {
Search.shutdown();
} catch (Exception e) {
throw new UnexpectedException (e);
}
This is easily done using Jobs with @ OnApplicationStart / Stop annotations .
The next step was to wean play to think it was a plugin. Playframework finds the modules in the classpath using the play.plugins file , in fact , with the usual archiver, this file was deleted from the jar file, and everything turned and twisted.
I hope my experience will be useful and will help save time for people who use Playframework in their work.
PS: Since I had to put the module in the lib folder, I also rebuilt it by correcting the bug with public fields. :)