Skip to content

Commit

Permalink
SOLR-16994: facilitate date-related FieldValueFeature extensions (doc…
Browse files Browse the repository at this point in the history
…Values=True only) (apache#1950)
  • Loading branch information
cpoerschke authored Oct 2, 2023
1 parent 03f656f commit e413210
Show file tree
Hide file tree
Showing 2 changed files with 122 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,17 @@ public FieldValueFeatureWeight(
}
}

/**
* Override this method in sub classes that wish to use not an absolute time but an interval
* such as document age or remaining shelf life relative to a specific date or relative to now.
*
* @param val value of the field
* @return value after transformation
*/
protected long readNumericDocValuesDate(long val) {
return val;
}

/**
* Return a FeatureScorer that uses docValues or storedFields if no docValues are present
*
Expand Down Expand Up @@ -261,6 +272,8 @@ private float readNumericDocValues() throws IOException {
} else if (NumberType.DOUBLE.equals(numberType)) {
// handle double value conversion
return (float) Double.longBitsToDouble(docValues.longValue());
} else if (NumberType.DATE.equals(numberType)) {
return readNumericDocValuesDate(docValues.longValue());
}
// just take the long value
return docValues.longValue();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,10 @@
package org.apache.solr.ltr.feature;

import java.io.IOException;
import java.time.Instant;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import org.apache.lucene.index.LeafReaderContext;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.Query;
Expand Down Expand Up @@ -692,6 +694,113 @@ public void testThatDateValuesAreCorrectlyParsed() throws Exception {
}
}

public static class RelativeDateFieldValueFeature extends FieldValueFeature {

private boolean since = false;
private boolean until = false;

public boolean getSince() {
return this.since;
}

public void setSince(boolean since) {
this.since = since;
}

public boolean getUntil() {
return this.until;
}

public void setUntil(boolean until) {
this.until = until;
}

public RelativeDateFieldValueFeature(String name, Map<String, Object> params) {
super(name, params);
}

@Override
protected void validate() throws FeatureException {
if (since != until) {
return;
}
throw new FeatureException(
getClass().getSimpleName() + ": exactly one of 'since' and 'until' must be provided");
}

@Override
public FeatureWeight createWeight(
IndexSearcher searcher,
boolean needsScores,
SolrQueryRequest request,
Query originalQuery,
Map<String, String[]> efi)
throws IOException {
return new FieldValueFeatureWeight(searcher, request, originalQuery, efi) {
private final long timeZero = Instant.parse("2000-01-01T00:00:00.000Z").toEpochMilli();

@Override
public long readNumericDocValuesDate(long val) {
if (since) return TimeUnit.MILLISECONDS.toMinutes(val - this.timeZero);
if (until) return TimeUnit.MILLISECONDS.toMinutes(this.timeZero - val);
return 0;
}
};
}
}

@Test
public void testRelativeDateFieldValueFeature() throws Exception {
final String field = "dvDateField";
for (boolean since : new boolean[] {false, true}) {
final String[][] inputsAndTests = {
new String[] {
"2000-01-01T00:00:00.000Z",
"/response/docs/[0]/=={'[fv]':'"
+ FeatureLoggerTestUtils.toFeatureVector(field, "0.0")
+ "'}"
},
new String[] {
"2000-01-01T00:01:02.003Z",
"/response/docs/[0]/=={'[fv]':'"
+ FeatureLoggerTestUtils.toFeatureVector(field, (since ? "1.0" : "-1.0"))
+ "'}"
},
new String[] {
"2000-01-01T01:02:03.004Z",
"/response/docs/[0]/=={'[fv]':'"
+ FeatureLoggerTestUtils.toFeatureVector(field, (since ? "62.0" : "-62.0"))
+ "'}"
}
};

final String fstore = "testRelativeDateFieldValueFeature" + field + "_" + since;
final String model = fstore + "-model";
loadFeature(
field,
RelativeDateFieldValueFeature.class.getName(),
fstore,
"{\"field\":\"" + field + "\", \"" + (since ? "since" : "until") + "\": true}");
loadModel(
model,
LinearModel.class.getName(),
new String[] {field},
fstore,
"{\"weights\":{\"" + field + "\":1.0}}");

for (String[] inputAndTest : inputsAndTests) {
assertU(adoc("id", "21", field, inputAndTest[0]));
assertU(commit());

final SolrQuery query = new SolrQuery("id:21");
query.add("rq", "{!ltr model=" + model + " reRankDocs=4}");
query.add("fl", "[fv]");

assertJQ("/query" + query.toQueryString(), inputAndTest[1]);
}
}
}

/**
* This class is used to track which specific FieldValueFeature is used so that we can test,
* whether the fallback mechanism works correctly.
Expand Down

0 comments on commit e413210

Please sign in to comment.