概述
Solr提供ValueSourceParser來實現自定義評分函數,在自定義評分函數中封裝評分邏輯,然後根據自定義評分函數計算的值進行排序。
準備數據
將數據導入solr
原始查詢
q=sdes:共和國
fq=spopulation:[ 500000000 TO * ]
fl=*,score
排序默認使用score得分排序,可發現巴西的評分(0.15021087)比中國評分(0.1201687)高,那麼可以利用自定義評分函數的值,來實現重新排序
自定義評分邏輯
//默認得分都是1.0分
float boot = 1.0f;
//如果sarea不存在或者爲小,則減去0.2分
if (StringUtils.isBlank(sarea) || "小".equals(sarea)) {
boot -= 0.2f;
}
//如果sname存在中,則增加0.2分
if (sname.contains("中")) {
boot += 0.2f;
}
//如果spopulation大於500000000,則增加0.5分
if (spopulation > 500000000) {
boot += 0.5f;
}
根據新的評分邏輯計算,巴西的評分(1.0),中國的評分(1.7)
編寫代碼
public class MyValueSourceParser extends ValueSourceParser {
private final Logger log = LoggerFactory.getLogger(MyValueSourceParser.class);
public MyValueSourceParser() {
super();
}
@Override
public ValueSource parse(FunctionQParser fp) throws SyntaxError {
/**
* 按順序取2個參數
*/
String arg1 = fp.parseArg(); //取到第一個參數
String arg2 = fp.parseArg(); //取到第二個參數
log.info("MyFilterQParserPlugin arg1=" + arg1);
log.info("MyFilterQParserPlugin arg2=" + arg2);
/**
* 獲取LocalParams
*/
SolrParams solrParams = fp.getLocalParams();
if (null != solrParams) {
Iterator<String> it = solrParams.getParameterNamesIterator();
while (it.hasNext()) {
final String name = it.next();
final String[] values = solrParams.getParams(name);
for (String v : values) {
log.info("LocalParams name:" + v);
}
}
}
/**
* 獲取Params
*/
solrParams = fp.getParams();
if (null != solrParams) {
Iterator<String> it = solrParams.getParameterNamesIterator();
while (it.hasNext()) {
final String name = it.next();
final String[] values = solrParams.getParams(name);
for (String v : values) {
log.info("Params " + name + ":" + v);
}
}
}
/**
*
* 獲取三個字段的信息
*/
ValueSource sareavs = getValueSource(fp, "id");
ValueSource spopulationvs = getValueSource(fp, "spopulation");
ValueSource snamevs = getValueSource(fp, "sname");
/**
* 將相關文檔的值傳給自定義的ValueSource方法,打分規則在自定義的ValueSource中定製
*/
MyValueSource myValueSource = new MyValueSource(sareavs, spopulationvs, snamevs);
return myValueSource;
}
/**
* 該方法是根據字段名,從FunctionQParser得到文檔該字段的相關信息
* @param fp
* @param arg
* @return
*/
public ValueSource getValueSource(FunctionQParser fp, String arg) {
if (arg == null) {
return null;
}
SchemaField f = fp.getReq().getSchema().getField(arg);
return f.getType().getValueSource(f, fp);
}
}
public class MyValueSource extends ValueSource {
private final Logger log = LoggerFactory.getLogger(MyValueSource.class);
private ValueSource sareavs;
private ValueSource spopulationvs;
private ValueSource snamevs;
public MyValueSource(ValueSource sareavs, ValueSource spopulationvs, ValueSource snamevs) {
this.sareavs = sareavs;
this.spopulationvs = spopulationvs;
this.snamevs = snamevs;
}
@Override
public FunctionValues getValues(Map context,AtomicReaderContext readerContext) throws IOException {
final FunctionValues sareafv = sareavs.getValues(context,readerContext);
final FunctionValues spopulationfv = spopulationvs.getValues(context,readerContext);
final FunctionValues snamefv = snamevs.getValues(context,readerContext);
return new FloatDocValues(this) {
/**
* 重寫floatVal方法,自定義打分排序規則
* @param doc
* @return
*/
@Override
public float floatVal(int doc) {
String sarea = sareafv.strVal(doc);
long spopulation = spopulationfv.longVal(doc);
String sname = snamefv.strVal(doc);
log.info(toString());
float boot = 1.0f;
if (StringUtils.isBlank(sarea) || "小".equals(sarea)) {
boot -= 0.2f;
}
if (sname.contains("中")) {
boot += 0.2f;
}
if (spopulation > 500000000) {
boot += 0.5f;
}
return boot;
}
@Override
public String toString(int doc) {
return name() + '(' + sareafv.strVal(doc) + ',' + spopulationfv.strVal(doc) + ',' + snamefv.strVal(doc) + ')';
}
};
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
} else if (obj == null) {
return false;
} else if (this.getClass() != obj.getClass()) {
return false;
} else {
MyValueSource other = (MyValueSource) obj;
if (this.sareavs == null) {
if (other.sareavs != null) {
return false;
}
} else if (!this.sareavs.equals(other.sareavs)) {
return false;
}
if (this.spopulationvs == null) {
if (other.spopulationvs != null) {
return false;
}
} else if (!this.spopulationvs.equals(other.spopulationvs)) {
return false;
}
if (this.snamevs == null) {
if (other.snamevs != null) {
return false;
}
} else if (!this.snamevs.equals(other.snamevs)) {
return false;
}
return true;
}
}
@Override
public int hashCode() {
int result = 1;
result = 31 * result + (this.sareavs == null ? 0 : this.sareavs.hashCode());
result = 31 * result + (this.spopulationvs == null ? 0 : this.spopulationvs.hashCode());
result = 31 * result + (this.snamevs == null ? 0 : this.snamevs.hashCode());
return result;
}
@Override
public String description() {
return name();
}
public String name() {
return "MyValueSource";
}
}
solrconfig配置
配置插件名稱和關聯類
<valueSourceParser name="myValueSource" class="cn.sing.plugin.valuesource.MyValueSourceParser" />
使用方式:
- sort={!func}myValueSource("1","2") asc
- fl=*,score,_val_:myValueSource("1","2")
lib路徑
將上面編寫的2個類打包放到lib引用的目錄中,lib也編寫在solrconfig配置中
<lib dir="D:\Soft\solr-cloud\solorconfig\testindex\javalib" regex=".*\.jar" />
重新查詢
q=sdes:共和國
fq=spopulation:[ 500000000 TO * ]
fl=*,score,_val_:myValueSource("1","2")
sort={!func}myValueSource("1","2") desc
執行日誌
INFO - 2020-02-18 16:02:01.755; cn.suning.plugin.valuesource.MyValueSourceParser; MyFilterQParserPlugin arg1=1
INFO - 2020-02-18 16:02:01.755; cn.suning.plugin.valuesource.MyValueSourceParser; MyFilterQParserPlugin arg2=2
INFO - 2020-02-18 16:02:01.755; cn.suning.plugin.valuesource.MyValueSourceParser; LocalParams v:myValueSource("1","2") desc
INFO - 2020-02-18 16:02:01.756; cn.suning.plugin.valuesource.MyValueSourceParser; LocalParams type:func
INFO - 2020-02-18 16:02:01.756; cn.suning.plugin.valuesource.MyValueSourceParser; Params defType:lucene
INFO - 2020-02-18 16:02:01.756; cn.suning.plugin.valuesource.MyValueSourceParser; Params rows:10
INFO - 2020-02-18 16:02:01.756; cn.suning.plugin.valuesource.MyValueSourceParser; Params distrib:false
INFO - 2020-02-18 16:02:01.756; cn.suning.plugin.valuesource.MyValueSourceParser; Params fl:id,score
INFO - 2020-02-18 16:02:01.756; cn.suning.plugin.valuesource.MyValueSourceParser; Params start:0
INFO - 2020-02-18 16:02:01.756; cn.suning.plugin.valuesource.MyValueSourceParser; Params fsv:true
INFO - 2020-02-18 16:02:01.757; cn.suning.plugin.valuesource.MyValueSourceParser; Params fq:spopulation:[ 500000000 TO * ]
INFO - 2020-02-18 16:02:01.757; cn.suning.plugin.valuesource.MyValueSourceParser; Params sort:{!func}myValueSource("1","2") desc
INFO - 2020-02-18 16:02:01.757; cn.suning.plugin.valuesource.MyValueSourceParser; Params shard.url:http://127.0.0.1:8891/solr/testindex_shard2_replica1/
INFO - 2020-02-18 16:02:01.757; cn.suning.plugin.valuesource.MyValueSourceParser; Params rows:10
INFO - 2020-02-18 16:02:01.757; cn.suning.plugin.valuesource.MyValueSourceParser; Params version:2
INFO - 2020-02-18 16:02:01.757; cn.suning.plugin.valuesource.MyValueSourceParser; Params q:sdes:����
INFO - 2020-02-18 16:02:01.757; cn.suning.plugin.valuesource.MyValueSourceParser; Params defType:lucene
INFO - 2020-02-18 16:02:01.758; cn.suning.plugin.valuesource.MyValueSourceParser; Params NOW:1582012921733
INFO - 2020-02-18 16:02:01.758; cn.suning.plugin.valuesource.MyValueSourceParser; Params isShard:true
INFO - 2020-02-18 16:02:01.758; cn.suning.plugin.valuesource.MyValueSourceParser; Params wt:javabin
INFO - 2020-02-18 16:02:01.759; org.apache.solr.core.SolrCore; [testindex_shard2_replica1] webapp=/solr path=/select params={distrib=false&fl=id,score&start=0&fsv=true&fq=spopulation:[+500000000+TO+*+]&sort={!func}myValueSource("1","2")+desc&shard.url=http://127.0.0.1:8891/solr/testindex_shard2_replica1/&rows=10&version=2&q=sdes:����&defType=lucene&NOW=1582012921733&isShard=true&wt=javabin} hits=0 status=0 QTime=6
INFO - 2020-02-18 16:02:01.790; org.apache.solr.core.SolrCore; [testindex_shard2_replica1] webapp=/solr path=/select params={q=sdes:����&indent=true&fl=*,score,_val_:myValueSource("1","2")&fq=spopulation:[+500000000+TO+*+]&sort={!func}myValueSource("1","2")+desc&wt=json} hits=2 status=0 QTime=57