This is an automated email from the ASF dual-hosted git repository.

cpoerschke pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/solr.git


The following commit(s) were added to refs/heads/main by this push:
     new e413210646b SOLR-16994: facilitate date-related FieldValueFeature 
extensions (docValues=True only) (#1950)
e413210646b is described below

commit e413210646bfdf1d5bc342d5b52ae5a4f0239c70
Author: Christine Poerschke <[email protected]>
AuthorDate: Mon Oct 2 11:48:23 2023 +0100

    SOLR-16994: facilitate date-related FieldValueFeature extensions 
(docValues=True only) (#1950)
---
 .../apache/solr/ltr/feature/FieldValueFeature.java |  13 +++
 .../solr/ltr/feature/TestFieldValueFeature.java    | 109 +++++++++++++++++++++
 2 files changed, 122 insertions(+)

diff --git 
a/solr/modules/ltr/src/java/org/apache/solr/ltr/feature/FieldValueFeature.java 
b/solr/modules/ltr/src/java/org/apache/solr/ltr/feature/FieldValueFeature.java
index bab34fa8d3e..583e080954c 100644
--- 
a/solr/modules/ltr/src/java/org/apache/solr/ltr/feature/FieldValueFeature.java
+++ 
b/solr/modules/ltr/src/java/org/apache/solr/ltr/feature/FieldValueFeature.java
@@ -129,6 +129,17 @@ public class FieldValueFeature extends Feature {
       }
     }
 
+    /**
+     * 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
      *
@@ -261,6 +272,8 @@ public class FieldValueFeature extends Feature {
         } 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();
diff --git 
a/solr/modules/ltr/src/test/org/apache/solr/ltr/feature/TestFieldValueFeature.java
 
b/solr/modules/ltr/src/test/org/apache/solr/ltr/feature/TestFieldValueFeature.java
index 8bed4efe7ed..b10d9d7f952 100644
--- 
a/solr/modules/ltr/src/test/org/apache/solr/ltr/feature/TestFieldValueFeature.java
+++ 
b/solr/modules/ltr/src/test/org/apache/solr/ltr/feature/TestFieldValueFeature.java
@@ -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;
@@ -692,6 +694,113 @@ public class TestFieldValueFeature extends TestRerankBase 
{
     }
   }
 
+  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.

Reply via email to