From 6ded27177beb743bdda0493fe3783a187da4e956 Mon Sep 17 00:00:00 2001 From: Olof-Joachim Frahm Date: Wed, 18 Nov 2015 01:13:05 +0100 Subject: [PATCH] Fix up the ABCL post a bit. --- abcl-and-lire.post | 76 +++++++++++++++++++++++++++++++++++----------------- 1 file changed, 51 insertions(+), 25 deletions(-) diff --git a/abcl-and-lire.post b/abcl-and-lire.post index bb1c1ca..fc1814f 100644 --- a/abcl-and-lire.post +++ b/abcl-and-lire.post @@ -30,7 +30,8 @@ Generally using JSS is a bit nicer than the plain Java FFI. After the contribs are loaded, JSS can be required and used: ``` -(require #:jss) +(require '#:abcl-contrib) +(require '#:jss) (use-package '#:jss) ``` @@ -53,7 +54,7 @@ load one from a pathname is a good start: ``` (defun read-image (pathname) - (#"read" 'javax.imageio.ImageIO (new 'java.io.FileInputStream (namestring pathname)))) + (#"read" 'javax.imageio.ImageIO (new 'java.io.File (namestring pathname)))) ``` To note here is the use of `NEW` from JSS with a symbol for the class @@ -62,10 +63,20 @@ side doesn't expect a Lisp object and the `#""` reader syntax from JSS to invoke the method `read` in a bit of a simpler way than using the FFI calls directly. -Since we can't "import" Java names, we're stuck with either using -symbols like this, or caching them in (shorter) variables. +JSS will automatically "import" Java names, so the same function can +simply be the following instead (provided that the names aren't +ambiguous): -For comparison, the raw FFI would be a bit more verbose: +``` +(defun read-image (pathname) + (#"read" 'ImageIO (new 'File (namestring pathname)))) +``` + +The names will be looked up again on every call though, so this option +isn't the best performing one. + +For comparison, the raw FFI would be a bit more verbose, but explicitely +specifies all names: ``` (defun read-image (pathname) @@ -96,13 +107,12 @@ separate parameter: ``` (defun build-index (index-name pathnames) (let ((global-document-builder - (new 'net.semanticmetadata.lire.builders.GlobalDocumentBuilder - (jclass "net.semanticmetadata.lire.imageanalysis.features.global.CEDD"))) + (new 'GlobalDocumentBuilder (find-java-class 'CEDD))) (index-writer (#"createIndexWriter" - 'net.semanticmetadata.lire.utils.LuceneUtils + 'LuceneUtils index-name +true+ - (jfield "net.semanticmetadata.lire.utils.LuceneUtils$AnalyzerType" "WhitespaceAnalyzer")))) + (get-java-field 'LuceneUtils$AnalyzerType "WhitespaceAnalyzer")))) (unwind-protect (dolist (pathname pathnames) (let ((pathname (namestring pathname))) @@ -111,9 +121,21 @@ separate parameter: (document (#"createDocument" global-document-builder image pathname))) (#"addDocument" index-writer document)) (format T " done.~%"))) - (#"closeWriter" 'net.semanticmetadata.lire.utils.LuceneUtils index-writer)))) + (#"closeWriter" 'LuceneUtils index-writer)))) ``` +**Note**: This code won't work on current ABCL as is, because the lookup +is disabled for for nested classes (those containing the dollar +character). Because of this, the `AnalyzerType` class would have to be +looked up as follows: + +``` +(jfield "net.semanticmetadata.lire.utils.LuceneUtils$AnalyzerType" "WhitespaceAnalyzer") +``` + +All in all nothing fancy, JSS takes care of a lot of typing as the names +are all unique enough. + The process is simply creating the document builder and index writer, reading all the files one by one and adding them to the index. There's no error checking at the moment though. @@ -128,7 +150,15 @@ Apart from that, this is mostly a direct transcription. Unfortunately written this way there's no point in creating a `WITH-OPEN-*` macro to automatically close the writer, however, looking at the `LuceneUtils` source this could be accomplished by directly calling `close` on the -writer object instead. +writer object instead - a corresponding macro might this then: + +``` +(defmacro with-open ((name value) &body body) + `(let ((,name ,value)) + (unwind-protect + (progn ,@body) + (#"close" ,name)))) +``` It would also be nice to have auto conversion using keywords for enum values instead of needing to look up the value manually. @@ -141,18 +171,17 @@ example, is done using an image searcher: ``` (defun query-index (index-name pathname) (let* ((image (read-image pathname)) - (index-reader (#"open" 'org.apache.lucene.index.DirectoryReader - (#"open" 'org.apache.lucene.store.FSDirectory - (#"get" 'java.nio.file.Paths index-name (jnew-array "java.lang.String" 0)))))) + (index-reader (#"open" 'DirectoryReader + (#"open" 'FSDirectory + (#"get" 'Paths index-name (jnew-array "java.lang.String" 0)))))) (unwind-protect - (let* ((image-searcher (new 'GenericFastImageSearcher 30 (jclass "net.semanticmetadata.lire.imageanalysis.features.global.CEDD"))) + (let* ((image-searcher (new 'GenericFastImageSearcher 30 (find-java-class 'CEDD))) (hits (#"search" image-searcher image index-reader))) (dotimes (i (#"length" hits)) (let ((found-pathname (#"getValues" (#"document" index-reader (#"documentID" hits i)) - (jfield "net.semanticmetadata.lire.builders.DocumentBuilder" - "FIELD_NAME_IDENTIFIER")))) + (get-java-field 'builders.DocumentBuilder "FIELD_NAME_IDENTIFIER")))) (format T "~F: ~A~%" (#"score" hits i) found-pathname)))) - (#"closeReader" 'net.semanticmetadata.lire.utils.LuceneUtils index-reader)))) + (#"closeReader" 'LuceneUtils index-reader)))) ``` To note here is that the `get` call on `java.nio.file.Paths` took way @@ -177,8 +206,6 @@ semantics. On the one end, we could imagine something akin to "Java in Lisp": ``` -(import '(javax.imageio.ImageIO java.io.FileInputStream)) - (defun read-image (pathname) (ImageIO/read (FileInputStream. pathname))) ``` @@ -192,15 +219,14 @@ the user point of view. They'd basically disallow a wide range of formerly legal Lisp names. ``` -(import '(javax.imageio.ImageIO java.io.FileInputStream)) - (defun read-image (pathname) (#"read" 'ImageIO (new 'FileInputStream pathname))) ``` -This way is the middle ground that would be possible. The one addition -to the current JSS system is the importing of Java names and -corresponding interaction with the FFI. +This way is the middle ground that we have now. The one addition here +could be that name lookup is done at macro expansion / compilation time, +so they are fixed one step before execution, whereas at the moment the +JSS reader macro will allow for very late bound name lookup instead. The similarity with CLOS would be the use of symbols for class names, but the distinction is still there, since there's not much in terms of -- 1.7.10.4