ãã¯ã¹ãã§ã¬ã³ã¡ã³ããšã³ãžã³éçºãããŠãå€å·ã§ãã åå ã¯ãsolr ã§ç¬èªåºæºãœãŒããå®çŸããæ¹æ³ãšããŠãã1.æ¢åã®function query ãçµã¿åããã§å®çŸããæ¹æ³ãã玹ä»ããŸããã®ã§ãä»åã¯ãã2. ç¬èªã®function query äœæããŠå®çŸããæ¹æ³ãã玹ä»ããããšæããŸãã solr ã®ãœãŒã¹ã³ãŒãç¢ºèª ãŸãã¯ãsolrã®function queryãã©ã®ããã«å®è£
ãããŠããããrecip颿°ã察象ã«èŠãŠã¿ãŸãã soïœr ã®ãœãŒã¹ã³ãŒããååŸããŠãé©åœãªãã£ã¬ã¯ããªã«å±éããŸãã wget http://ftp.yz.yamagata-u.ac.jp/pub/network/apache/lucene/solr/4.6.1/solr-4.6.1-src.tgz tar xvzf solr-4.6.1-src.tgz recip颿° ã®èª¬æãèªããšãrecip(x,m,a,b) ã®ããã«ã¯ãšãªã§æå®ããxã¯ããã¥ã¡ã³ãã®ãã£ãŒã«ãåãããããã¯æ°å€ãè¿ã颿°ããã®ä»ã®ãmãaãbã¯ãæ°å€å®æ°ã§ãããšèšè¿°ãããŠããŸãã solr-4.6.1/solr/core/src/java/org/apache/solr/search/ValueSourceParser.java ã®recip颿°ã«é¢é£ããéšå 151 addParser("recip", new ValueSourceParser() { 152 @Override 153 public ValueSource parse(FunctionQParser fp) throws SyntaxError { 154 ValueSource source = fp.parseValueSource(); 155 float m = fp.parseFloat(); 156 float a = fp.parseFloat(); 157 float b = fp.parseFloat(); 158 return new ReciprocalFloatFunction(source, m, a, b); 159 } 160 }); ãèŠããšãããã¥ã¡ã³ãã«äŸåãããã£ãŒã«ãå€ãValueSourceã¯ã©ã¹ã®å€æ° sourceãšããŠãããã¥ã¡ã³ãã«äŸåããªããã®ä»ã¯ãfloatåã®å€æ°mãaãb ãšããŠè§£éãããããåŒæ°ã«ReciproacalFloatfunction ã¯ã©ã¹ãçæããŠè¿ããŠããããšãåãããŸãã ReciproacalFloatfunctionã®äžèº«ãã¿ããšãæå€ãšç°¡åãªã³ãŒãã§ããããšãåãããŸãã solr-4.6.1/lucene/queries/src/java/org/apache/lucene/queries/function/valuesource/ReciprocalFloatFunction.java ããããããŒã¹ã«ããŠäœæããŠããã°ããããã§ãã plugin jar ãã¡ã€ã«äœæ ReciprocalFloatFunction.java ããŸãããŠãmyfunc(x,y,a,b,c,d) ãšãããããã¥ã¡ã³ããã£ãŒã«ãå€x, y ãšãã®ä»ã4ã€ã®æ°å€å®æ°ãå
¥åãšããa x x + b x y + c y y + d x + e y + f ã®èšç®çµæãè¿ãç¬èªã¯ã©ã¹ãå®è£
ããŠã¿ãã®ãã以äžã®ãã¡ã€ã«ã§ãã MyFloatFunction.java package jp.co.homes.functionquery; import org.apache.lucene.index.AtomicReaderContext; import org.apache.lucene.queries.function.FunctionValues; import org.apache.lucene.queries.function.ValueSource; import org.apache.lucene.queries.function.docvalues.FloatDocValues; import org.apache.lucene.search.IndexSearcher; import java.io.IOException; import java.util.Map; public class MyFloatFunction extends ValueSource { protected final ValueSource x; protected final ValueSource y; protected final float a; protected final float b; protected final float c; protected final float d; protected final float e; protected final float f; /** * f(x,y,a,b,c,d,e,f) = a*x*x + b*x*y + c*y*y + d*x + e*y + f */ public MyFloatFunction(ValueSource x, ValueSource y, float a, float b, float c, float d, float e, float f) { this .x = x; this .y = y; this .a = a; this .b = b; this .c = c; this .d = d; this .e = e; this .f = f; } @Override public FunctionValues getValues(Map context, AtomicReaderContext readerContext) throws IOException { final FunctionValues xVals = x.getValues(context, readerContext); final FunctionValues yVals = y.getValues(context, readerContext); return new FloatDocValues( this ) { @Override public float floatVal( int doc) { float x = xVals.floatVal(doc); float y = yVals.floatVal(doc); return a*x*x + b*x*y + c*y*y + d*x + e*y + f; } @Override public String toString( int doc) { String xd = xVals.toString(doc); String yd = yVals.toString(doc); return Float.toString(a) + "*" + xd + "*" + xd + '+' + Float.toString(b) + "*" + xd + "*" + yd + '+' + Float.toString(c) + "*" + yd + "*" + yd + '+' + Float.toString(d) + "*" + xd + '+' + Float.toString(e) + "*" + yd + '+' + Float.toString(f); } }; } @Override public int hashCode() { int h = Float.floatToIntBits(a) + Float.floatToIntBits(b) + Float.floatToIntBits(c) + Float.floatToIntBits(d) + Float.floatToIntBits(e) + Float.floatToIntBits(f); h ^= (h << 13 ) | (h >>> 20 ); return h + (Float.floatToIntBits(b)) + x.hashCode() + y.hashCode(); } @Override public boolean equals(Object o) { if (MyFloatFunction. class != o.getClass()) return false ; MyFloatFunction other = (MyFloatFunction)o; return this .a == other.a && this .b == other.b && this .c == other.c && this .d == other.d && this .e == other.e && this .f == other.f && this .x.equals(other.x) && this .y.equals(other.y); } } 次ã«ãæ€çŽ¢ã¯ãšãªã«myfunc(x,y,a,b,c,d,e,f)ãšããæåå(x,yã¯ä»»æã®æ°å€ãã£ãŒã«ãåãa-f ã¯æ°å€å®æ°)ã äžããããå Žåã«ãåŒæ°ãè§£éããŠMyFloatFunctionã¯ã©ã¹ãäœæããŠè¿ãã¯ã©ã¹ãå®è£
ããŸãã HomesValueSourceParser.java package jp.co.homes.functionquery; import org.apache.lucene.queries.function.ValueSource; import org.apache.solr.common.util.NamedList; import org.apache.solr.search.SyntaxError; import org.apache.solr.search.FunctionQParser; import org.apache.solr.search.ValueSourceParser; public class HomesValueSourceParser extends ValueSourceParser { @Override public void init(NamedList namedList) { } @Override public ValueSource parse(FunctionQParser fp) throws SyntaxError { ValueSource x = fp.parseValueSource(); ValueSource y = fp.parseValueSource(); float a = fp.parseFloat(); float b = fp.parseFloat(); float c = fp.parseFloat(); float d = fp.parseFloat(); float e = fp.parseFloat(); float f = fp.parseFloat(); return new MyFloatFunction(x, y, a, b, c, d, e, f); } } ãã®äºã€ã®ãã¡ã€ã«ããååã€ã³ã¹ããŒã«ããsolrã®ãã£ã¬ã¯ããªã以äžã®jarãã¡ã€ã« solr-4.6.1/example/solr-webapp/webapp/WEB-INF/lucene-core-4.6.1.jar solr-4.6.1/example/solr-webapp/webapp/WEB-INF/lucene-queries-4.6.1.jar solr-4.6.1/example/solr-webapp/webapp/WEB-INF/lucene-queryparser-4.6.1.jar solr-4.6.1/example/solr-webapp/webapp/WEB-INF/solr-core-4.6.1.jar solr-4.6.1/example/solr-webapp/webapp/WEB-INF/solr-solrj-4.6.1.jar ã«pathã«éããŠã³ã³ãã€ã«ããŠãhomes-function-query.jar ãšããjar ãã¡ã€ã«ãäœæããŸãã èšå® ååèšå®ããsolrã§ããã®ãã©ã°ã€ã³ã䜿ããããã«ããŸãã ãŸããcollection1ãã©ã«ãã®äžã«libãã£ã¬ã¯ããªãäœæãããã®äžã«ãäœæããjar ãã¡ã€ã«ãã³ããŒããŸãã mkdir solr-4.6.1/example/solr/collection1/lib cp homes-function-query-plugin.jar solr-4.6.1/example/solr/collection1/lib 次ã«ã solr-4.6.1/example/solr/collection1/conf/solrconfig.xml ã®60è¡ç®ã«ä»¥äžã®ãããªäºè¡ã远å ããŸãã <lib dir = "./lib" /> <valueSourceParser name = "myfunc" class = "jp.co.homes.functionquery.HomesValueSourceParser" /> åäœç¢ºèª solr ãèµ·åããŸãã cd ./solr-4.6.1/example java -jar start.jar & æ°ããäœæããmyfunc颿°ãæå®ããã¯ãšãªãå®è¡ããŠã¿ãŸãã http://localhost:8983/solr/collection1/select?q=*:*&fl=x,y,myfunc(x,y,1,2,3,4,5,6) å®è¡çµæ <result name = "response" numFound = "6" start = "0" > <doc> <float name = "x" > 1.0 </float> <float name = "y" > 4.0 </float> <float name = "myfunc(x,y,1,2,3,4,5,6)" > 87.0 </float> </doc> <doc> <float name = "x" > 2.0 </float> <float name = "y" > 5.0 </float> <float name = "myfunc(x,y,1,2,3,4,5,6)" > 138.0 </float> </doc> <doc> <float name = "x" > 3.0 </float> <float name = "y" > 6.0 </float> <float name = "myfunc(x,y,1,2,3,4,5,6)" > 201.0 </float> </doc> <doc> <float name = "x" > 1.0 </float> <float name = "y" > 4.0 </float> <float name = "myfunc(x,y,1,2,3,4,5,6)" > 87.0 </float> </doc> <doc> <float name = "x" > 2.0 </float> <float name = "y" > 5.0 </float> <float name = "myfunc(x,y,1,2,3,4,5,6)" > 138.0 </float> </doc> <doc> <float name = "y" > 6.0 </float> <float name = "myfunc(x,y,1,2,3,4,5,6)" > 144.0 </float> </doc> </result> æ£ããèšç®ã§ããŠããããã§ãã æåŸã®xå€ã¯æ¬ æããŠãããããxã0ãšããŠæ±ãããŠããŸãããã£ãŒã«ãå€ãæ¬ æããŠããå Žåã«0ãšæ±ããããªãå Žåã«ã¯ã if (xVals.exists(doc) { ... } ã®ããã«ããŠæ¬ æå€ã®å Žåã®åŠçã远å ããå¿
èŠããããŸãã é床æ¯èŒ function query ã®çµã¿åãããšãç¬èª function query ã§ã©ã®çšåºŠé床ã«å·®ãåºãŠããããç°¡åãªæ€èšŒãããŠã¿ãŸããã ããŒã¿éãå°ãªããšå·®ãåºãŠããªãã®ã§ã100äžä»¶ã®ããŒã¿ã远å åŸããã£ãã·ã¥ã圱é¿ããªããããæ°å€å®æ°ã倿Žããªããã以äžã¯ãšãªã®QTimeã®5åå¹³åãèšç®ããŠã¿ãŸããã æ¢åfunction queryã®çµã¿åãã http://localhost:8983/solr/collection1/select?q=*:*&fl=x,y&sort=sum(product(pow(x,2),1),product(product(x,y),2), product(pow(y,2),3),product(x,4),product(y,5),6) desc ç¬èªfunction query http://localhost:8983/solr/collection1/select?q=*:*&sort=myfunc(x,y,1,2,3,4,5,6) desc çµæ function query çµã¿åãã å¹³åQTime 201ms ç¬èª function query å¹³åQTime 19ms myfuncã®æ¹ããçžåœé«éã§ããããšãåãããŸããfunction queryã®çµã¿åããã§ã¯ãåããã£ãŒã«ãã« äœåºŠãã¢ã¯ã»ã¹ãçºçããŠããŸãã®ã«å¯ŸããŠãç¬èª function query ã®æ¹ã¯1åããçºçããªããªã©ã ããŒã¿ã¢ã¯ã»ã¹ãå¹çåãããŠããã®ãåå ãšæãããŸãã ãŸãšã æã£ããããç°¡åã«ãç¬èªã®function query ãäœæããããšãã§ããŸããã ãã®æ¹æ³ã®å Žåãsolrã®queryã«ããã®ãŸãŸåã蟌ãã§äœ¿ããã®ã§å¿çšç¯å²ãåºãã®ããã€ã³ãã§ã 倧æµã®çšéã«ã¯ãããã§ååã§ã¯ãªãããšæããŸãã æ¬¡åãã ç¬èªã®search component ãäœæããŠå®çŸ ã ã«ç¶ããŸãã