You are viewing a plain text version of this content. The canonical link for it is here.
Posted to issues@lucene.apache.org by GitBox <gi...@apache.org> on 2020/06/26 21:54:18 UTC

[GitHub] [lucene-solr] tflobbe opened a new pull request #1620: SOLR-14590 : Alternative approach

tflobbe opened a new pull request #1620:
URL: https://github.com/apache/lucene-solr/pull/1620


   This implements the "Approach 2"  suggested by Varun here: https://github.com/apache/lucene-solr/pull/1616#discussion_r446404384


----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



---------------------------------------------------------------------
To unsubscribe, e-mail: issues-unsubscribe@lucene.apache.org
For additional commands, e-mail: issues-help@lucene.apache.org


[GitHub] [lucene-solr] dsmiley commented on a change in pull request #1620: SOLR-14590 : Add support for Lucene's FeatureField in Solr

Posted by GitBox <gi...@apache.org>.
dsmiley commented on a change in pull request #1620:
URL: https://github.com/apache/lucene-solr/pull/1620#discussion_r446488540



##########
File path: solr/core/src/java/org/apache/solr/schema/RankField.java
##########
@@ -0,0 +1,140 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.solr.schema;
+
+import java.io.IOException;
+import java.util.Map;
+
+import org.apache.lucene.document.FeatureField;
+import org.apache.lucene.index.IndexableField;
+import org.apache.lucene.index.IndexableFieldType;
+import org.apache.lucene.index.Term;
+import org.apache.lucene.search.Query;
+import org.apache.lucene.search.SortField;
+import org.apache.lucene.search.TermQuery;
+import org.apache.solr.common.SolrException;
+import org.apache.solr.response.TextResponseWriter;
+import org.apache.solr.search.QParser;
+import org.apache.solr.search.RankQParserPlugin;
+import org.apache.solr.uninverting.UninvertingReader.Type;
+
+/**
+ * <p>
+ * {@code RankField}s can be used to store scoring factors to improve document ranking. They should be used
+ * in combination with {@link RankQParserPlugin}. To use:
+ * </p>
+ * <p>
+ * Define the {@code RankField} {@code fieldType} in your schema:
+ * </p>
+ * <pre class="prettyprint">
+ * &lt;fieldType name="rank" class="solr.RankField" /&gt;
+ * </pre>
+ * <p>
+ * Add fields to the schema, i.e.:
+ * </p>
+ * <pre class="prettyprint">
+ * &lt;field name="rank_1" type="rank" /&gt;
+ * </pre>
+ * 
+ * Query using the {@link RankQParserPlugin}, for example
+ * <pre class="prettyprint">
+ * http://localhost:8983/solr/techproducts?q=memory _query_:{!rank f='rank_1', function='log' scalingFactor='1.2'}
+ * </pre>
+ * 
+ * @see RankQParserPlugin
+ * @lucene.experimental
+ * @since 8.6
+ */
+public class RankField extends FieldType {
+  
+  /*
+   * While the user can create multiple RankFields, internally we use a single Lucene field,
+   * and we map the Solr field name to the "feature" in Lucene's FeatureField. This is mainly
+   * to simplify the user experience.
+   */
+  public static final String INTERNAL_RANK_FIELD_NAME = "_internal_rank_field";

Review comment:
       should end with a final underscore as well like our other internal fields

##########
File path: solr/core/src/java/org/apache/solr/schema/RankField.java
##########
@@ -0,0 +1,140 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.solr.schema;
+
+import java.io.IOException;
+import java.util.Map;
+
+import org.apache.lucene.document.FeatureField;
+import org.apache.lucene.index.IndexableField;
+import org.apache.lucene.index.IndexableFieldType;
+import org.apache.lucene.index.Term;
+import org.apache.lucene.search.Query;
+import org.apache.lucene.search.SortField;
+import org.apache.lucene.search.TermQuery;
+import org.apache.solr.common.SolrException;
+import org.apache.solr.response.TextResponseWriter;
+import org.apache.solr.search.QParser;
+import org.apache.solr.search.RankQParserPlugin;
+import org.apache.solr.uninverting.UninvertingReader.Type;
+
+/**
+ * <p>
+ * {@code RankField}s can be used to store scoring factors to improve document ranking. They should be used
+ * in combination with {@link RankQParserPlugin}. To use:
+ * </p>
+ * <p>
+ * Define the {@code RankField} {@code fieldType} in your schema:
+ * </p>
+ * <pre class="prettyprint">
+ * &lt;fieldType name="rank" class="solr.RankField" /&gt;
+ * </pre>
+ * <p>
+ * Add fields to the schema, i.e.:
+ * </p>
+ * <pre class="prettyprint">
+ * &lt;field name="rank_1" type="rank" /&gt;
+ * </pre>
+ * 
+ * Query using the {@link RankQParserPlugin}, for example
+ * <pre class="prettyprint">
+ * http://localhost:8983/solr/techproducts?q=memory _query_:{!rank f='rank_1', function='log' scalingFactor='1.2'}
+ * </pre>
+ * 
+ * @see RankQParserPlugin
+ * @lucene.experimental
+ * @since 8.6
+ */
+public class RankField extends FieldType {
+  
+  /*
+   * While the user can create multiple RankFields, internally we use a single Lucene field,
+   * and we map the Solr field name to the "feature" in Lucene's FeatureField. This is mainly
+   * to simplify the user experience.
+   */
+  public static final String INTERNAL_RANK_FIELD_NAME = "_internal_rank_field";

Review comment:
       might simply \_rank\_ be fine?  The "internal" aspect is implied by the leading/trailing underscore, and I don't think _any_ field needs to have "field" in its name ;-)




----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



---------------------------------------------------------------------
To unsubscribe, e-mail: issues-unsubscribe@lucene.apache.org
For additional commands, e-mail: issues-help@lucene.apache.org


[GitHub] [lucene-solr] vthacker commented on a change in pull request #1620: SOLR-14590 : Add support for Lucene's FeatureField in Solr

Posted by GitBox <gi...@apache.org>.
vthacker commented on a change in pull request #1620:
URL: https://github.com/apache/lucene-solr/pull/1620#discussion_r447418777



##########
File path: solr/core/src/test/org/apache/solr/schema/RankFieldTest.java
##########
@@ -0,0 +1,261 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.solr.schema;
+
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+
+import org.apache.lucene.index.LeafReader;
+import org.apache.lucene.util.BytesRef;
+import org.apache.solr.SolrTestCaseJ4;
+import org.junit.BeforeClass;
+import org.junit.Ignore;
+
+public class RankFieldTest extends SolrTestCaseJ4 {
+  
+  private static final String RANK_1 = "rank_1";
+  private static final String RANK_2 = "rank_2";
+
+  @BeforeClass
+  public static void beforeClass() throws Exception {
+    initCore("solrconfig-minimal.xml","schema-rank-fields.xml");
+  }
+  
+  @Override
+  public void setUp() throws Exception {
+    clearIndex();
+    assertU(commit());
+    super.setUp();
+  }
+  
+  public void testInternalFieldName() {
+    assertEquals("RankField.INTERNAL_RANK_FIELD_NAME changed in an incompatible way",
+        "_rank_", RankField.INTERNAL_RANK_FIELD_NAME);
+  }
+
+  public void testBasic() {
+    assertNotNull(h.getCore().getLatestSchema().getFieldOrNull(RANK_1));
+    assertEquals(RankField.class, h.getCore().getLatestSchema().getField(RANK_1).getType().getClass());
+  }
+  
+  public void testBadFormat() {
+    ignoreException("Expecting float");
+    assertFailedU(adoc(
+        "id", "1",
+        RANK_1, "foo"
+        ));
+
+    assertFailedU(adoc(
+        "id", "1",
+        RANK_1, "1.2.3"
+        ));
+    
+    unIgnoreException("Expecting float");
+    
+    ignoreException("must be finite");
+    assertFailedU(adoc(
+        "id", "1",
+        RANK_1, Float.toString(Float.POSITIVE_INFINITY)
+        ));
+
+    assertFailedU(adoc(
+        "id", "1",
+        RANK_1, Float.toString(Float.NEGATIVE_INFINITY)
+        ));
+    
+    assertFailedU(adoc(
+        "id", "1",
+        RANK_1, Float.toString(Float.NaN)
+        ));
+    
+    unIgnoreException("must be finite");
+    
+    ignoreException("must be a positive");
+    assertFailedU(adoc(
+        "id", "1",
+        RANK_1, Float.toString(-0.0f)
+        ));
+
+    assertFailedU(adoc(
+        "id", "1",
+        RANK_1, Float.toString(-1f)
+        ));
+
+    assertFailedU(adoc(
+        "id", "1",
+        RANK_1, Float.toString(0.0f)
+        ));
+    unIgnoreException("must be a positive");
+  }
+  
+  public void testAddRandom() {
+    for (int i = 0 ; i < random().nextInt(TEST_NIGHTLY ? 10000 : 100); i++) {
+      assertU(adoc(
+          "id", String.valueOf(i),
+          RANK_1, Float.toString(random().nextFloat())
+          ));
+    }
+    assertU(commit());
+  }
+  
+  public void testSkipEmpty() {
+    assertU(adoc(
+        "id", "1",
+        RANK_1, ""
+        ));
+  }
+  
+  public void testBasicAdd() throws IOException {
+    assertU(adoc(
+        "id", "testBasicAdd",
+        RANK_1, "1"
+        ));
+    assertU(commit());
+    //assert that the document made it in
+    assertQ(req("q", "id:testBasicAdd"), "//*[@numFound='1']");
+    h.getCore().withSearcher((searcher) -> {
+      LeafReader reader = searcher.getIndexReader().getContext().leaves().get(0).reader();
+      // assert that the field made it in
+      assertNotNull(reader.getFieldInfos().fieldInfo(RankField.INTERNAL_RANK_FIELD_NAME));
+      // assert that the feature made it in
+      assertTrue(reader.terms(RankField.INTERNAL_RANK_FIELD_NAME).iterator().seekExact(new BytesRef(RANK_1.getBytes(StandardCharsets.UTF_8))));
+      return null;
+    });
+  }
+  
+  public void testMultipleRankFields() throws IOException {
+    assertU(adoc(
+        "id", "testMultiValueAdd",
+        RANK_1, "1",
+        RANK_2, "2"
+        ));
+    assertU(commit());
+    //assert that the document made it in
+    assertQ(req("q", "id:testMultiValueAdd"), "//*[@numFound='1']");
+    h.getCore().withSearcher((searcher) -> {
+      LeafReader reader = searcher.getIndexReader().getContext().leaves().get(0).reader();
+      // assert that the field made it in
+      assertNotNull(reader.getFieldInfos().fieldInfo(RankField.INTERNAL_RANK_FIELD_NAME));
+      // assert that the features made it in
+      assertTrue(reader.terms(RankField.INTERNAL_RANK_FIELD_NAME).iterator().seekExact(new BytesRef(RANK_2.getBytes(StandardCharsets.UTF_8))));
+      assertTrue(reader.terms(RankField.INTERNAL_RANK_FIELD_NAME).iterator().seekExact(new BytesRef(RANK_1.getBytes(StandardCharsets.UTF_8))));
+      return null;
+    });
+  }
+  
+  public void testSortFails() throws IOException {
+    assertU(adoc(
+        "id", "testSortFails",
+        RANK_1, "1"
+        ));
+    assertU(commit());
+    assertQEx("Can't sort on rank field", req(
+        "q", "id:testSortFails",
+        "sort", RANK_1 + " desc"), 400);
+  }
+  
+  @Ignore("We currently don't fail these kinds of requests with other field types")
+  public void testFacetFails() throws IOException {
+    assertU(adoc(
+        "id", "testFacetFails",
+        RANK_1, "1"
+        ));
+    assertU(commit());
+    assertQEx("Can't facet on rank field", req(
+        "q", "id:testFacetFails",
+        "facet", "true",
+        "facet.field", RANK_1), 400);
+  }
+  
+  public void testTermQuery() throws IOException {
+    assertU(adoc(
+        "id", "testTermQuery",
+        RANK_1, "1",
+        RANK_2, "1"
+        ));
+    assertU(adoc(
+        "id", "testTermQuery2",
+        RANK_1, "1"
+        ));
+    assertU(commit());
+    assertQ(req("q", RANK_1 + ":*"), "//*[@numFound='2']");
+    assertQ(req("q", RANK_1 + ":[* TO *]"), "//*[@numFound='2']");
+    assertQ(req("q", RANK_2 + ":*"), "//*[@numFound='1']");
+    assertQ(req("q", RANK_2 + ":[* TO *]"), "//*[@numFound='1']");
+    
+    assertQEx("Term queries not supported", req("q", RANK_1 + ":1"), 400);
+    assertQEx("Range queries not supported", req("q", RANK_1 + ":[1 TO 10]"), 400);
+  }
+  
+  
+  public void testResponseQuery() throws IOException {
+    assertU(adoc(
+        "id", "testResponseQuery",
+        RANK_1, "1"
+        ));
+    assertU(commit());
+    // Ignore requests to retrieve rank
+    assertQ(req("q", RANK_1 + ":*",
+        "fl", "id," + RANK_1),
+        "//*[@numFound='1']",
+        "count(//result/doc[1]/str)=1");
+  }
+  
+  public void testRankQParserQuery() throws IOException {
+    assertU(adoc(
+        "id", "1",
+        "str_field", "foo",
+        RANK_1, "1",
+        RANK_2, "2"
+        ));
+    assertU(adoc(
+        "id", "2",
+        "str_field", "foo",
+        RANK_1, "2",
+        RANK_2, "1"
+        ));
+    assertU(commit());
+    assertQ(req("q", "str_field:foo _query_:{!rank f='" + RANK_1 + "' function='log' scalingFactor='1'}"),
+        "//*[@numFound='2']",
+        "//result/doc[1]/str[@name='id'][.='2']",
+        "//result/doc[2]/str[@name='id'][.='1']");
+    
+    assertQ(req("q", "str_field:foo _query_:{!rank f='" + RANK_2 + "' function='log' scalingFactor='1'}"),
+        "//*[@numFound='2']",
+        "//result/doc[1]/str[@name='id'][.='1']",
+        "//result/doc[2]/str[@name='id'][.='2']");
+    
+    assertQ(req("q", "foo",
+        "defType", "dismax",
+        "qf", "str_field^10",
+        "bq", "{!rank f='" + RANK_1 + "' function='log' scalingFactor='1'}"
+        ),
+        "//*[@numFound='2']",
+        "//result/doc[1]/str[@name='id'][.='2']",
+        "//result/doc[2]/str[@name='id'][.='1']");
+    
+    assertQ(req("q", "foo",
+        "defType", "dismax",
+        "qf", "str_field^10",
+        "bq", "{!rank f='" + RANK_2 + "' function='log' scalingFactor='1'}"
+        ),
+        "//*[@numFound='2']",
+        "//result/doc[1]/str[@name='id'][.='1']",
+        "//result/doc[2]/str[@name='id'][.='2']");
+  }

Review comment:
       I manually checked the 'score' from these two runs to ensure that the score was changing! Would it make sense to add this as a test?
   
   ```
   String rsp = h.query(req("q", "foo",
           "defType", "dismax",
           "qf", "str_field^10",
           "fl", "*,score"
       ));
   
       rsp = h.query(req("q", "foo",
           "defType", "dismax",
           "qf", "str_field^10",
           "fl", "*,score",
           "bq", "{!rank f='" + RANK_2 + "' function='log' scalingFactor='1'}"
       ));
   ```




----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



---------------------------------------------------------------------
To unsubscribe, e-mail: issues-unsubscribe@lucene.apache.org
For additional commands, e-mail: issues-help@lucene.apache.org


[GitHub] [lucene-solr] tflobbe commented on a change in pull request #1620: SOLR-14590 : Alternative approach

Posted by GitBox <gi...@apache.org>.
tflobbe commented on a change in pull request #1620:
URL: https://github.com/apache/lucene-solr/pull/1620#discussion_r446435394



##########
File path: solr/core/src/java/org/apache/solr/schema/RankField.java
##########
@@ -0,0 +1,92 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.solr.schema;
+
+import java.io.IOException;
+import java.util.Map;
+
+import org.apache.lucene.document.FeatureField;
+import org.apache.lucene.index.IndexableField;
+import org.apache.lucene.index.IndexableFieldType;
+import org.apache.lucene.index.Term;
+import org.apache.lucene.search.Query;
+import org.apache.lucene.search.SortField;
+import org.apache.lucene.search.TermQuery;
+import org.apache.solr.common.SolrException;
+import org.apache.solr.response.TextResponseWriter;
+import org.apache.solr.search.QParser;
+import org.apache.solr.uninverting.UninvertingReader.Type;
+
+public class RankField extends FieldType {
+  
+  public static final String INTERNAL_RANK_FIELD_NAME = "_internal_rank_field";
+
+  @Override
+  public Type getUninversionType(SchemaField sf) {
+    throw null;
+  }
+
+  @Override
+  public void write(TextResponseWriter writer, String name, IndexableField f) throws IOException {
+  }
+  
+  @Override
+  protected void init(IndexSchema schema, Map<String,String> args) {
+    super.init(schema, args);
+    if (schema.getFieldOrNull(INTERNAL_RANK_FIELD_NAME) != null) {
+      throw new SolrException(SolrException.ErrorCode.SERVER_ERROR, "A field named \"" + INTERNAL_RANK_FIELD_NAME + "\" can't be defined in the schema");
+    }
+    for (int prop:new int[] {STORED, DOC_VALUES, OMIT_TF_POSITIONS, SORT_MISSING_FIRST, SORT_MISSING_LAST}) {
+      if ((trueProperties & prop) != 0) {
+        throw new SolrException(SolrException.ErrorCode.SERVER_ERROR, "Property \"" + getPropertyName(prop) + "\" can't be set to true in RankFields");
+      }
+    }
+    for (int prop:new int[] {UNINVERTIBLE, INDEXED, MULTIVALUED}) {
+      if ((falseProperties & prop) != 0) {
+        throw new SolrException(SolrException.ErrorCode.SERVER_ERROR, "Property \"" + getPropertyName(prop) + "\" can't be set to false in RankFields");
+      }
+    }
+    properties &= ~(UNINVERTIBLE | STORED | DOC_VALUES);
+    
+  }
+
+  @Override
+  protected IndexableField createField(String name, String val, IndexableFieldType type) {
+    if (val == null || val.isEmpty()) {
+      return null;
+    }
+    float featureValue;
+    try {
+      featureValue = Float.parseFloat(val);
+    } catch (NumberFormatException nfe) {
+      throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, "Error while creating field '" + name + "' from value '" + val + "'. Expecting float.", nfe);
+    }
+    return new FeatureField(INTERNAL_RANK_FIELD_NAME, name, featureValue);
+  }
+
+  @Override
+  public Query getFieldQuery(QParser parser, SchemaField field, String externalVal) {

Review comment:
       Good idea. I'll add that




----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



---------------------------------------------------------------------
To unsubscribe, e-mail: issues-unsubscribe@lucene.apache.org
For additional commands, e-mail: issues-help@lucene.apache.org


[GitHub] [lucene-solr] vthacker commented on a change in pull request #1620: SOLR-14590 : Add support for Lucene's FeatureField in Solr

Posted by GitBox <gi...@apache.org>.
vthacker commented on a change in pull request #1620:
URL: https://github.com/apache/lucene-solr/pull/1620#discussion_r447412254



##########
File path: solr/core/src/java/org/apache/solr/search/RankQParserPlugin.java
##########
@@ -0,0 +1,158 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.solr.search;
+
+import java.util.Locale;
+import java.util.Objects;
+
+import org.apache.lucene.document.FeatureField;
+import org.apache.lucene.search.Query;
+import org.apache.solr.common.params.SolrParams;
+import org.apache.solr.request.SolrQueryRequest;
+import org.apache.solr.schema.RankField;
+import org.apache.solr.schema.SchemaField;
+/**
+ * {@code RankQParserPlugin} can be used to introduce document-depending scoring factors to ranking.
+ * While this {@code QParser} delivers a (subset of) functionality already available via {@link FunctionQParser},
+ * the benefit is that {@code RankQParserPlugin} can be used in combination with the {@code minExactCount} to
+ * use BlockMax-WAND algorithm (skip non-competitive documents) to provide faster responses. 
+ * 
+ *  @see RankField
+ * 
+ * @lucene.experimental
+ * @since 8.6
+ */
+public class RankQParserPlugin extends QParserPlugin {
+  
+  public static final String NAME = "rank";
+  public static final String FIELD = "f";

Review comment:
       👍 All parsers in https://lucene.apache.org/solr/guide/8_5/other-parsers.html that expect a field use `f` as the key




----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



---------------------------------------------------------------------
To unsubscribe, e-mail: issues-unsubscribe@lucene.apache.org
For additional commands, e-mail: issues-help@lucene.apache.org


[GitHub] [lucene-solr] vthacker commented on a change in pull request #1620: SOLR-14590 : Add support for Lucene's FeatureField in Solr

Posted by GitBox <gi...@apache.org>.
vthacker commented on a change in pull request #1620:
URL: https://github.com/apache/lucene-solr/pull/1620#discussion_r447419952



##########
File path: solr/core/src/test/org/apache/solr/schema/RankFieldTest.java
##########
@@ -0,0 +1,261 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.solr.schema;
+
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+
+import org.apache.lucene.index.LeafReader;
+import org.apache.lucene.util.BytesRef;
+import org.apache.solr.SolrTestCaseJ4;
+import org.junit.BeforeClass;
+import org.junit.Ignore;
+
+public class RankFieldTest extends SolrTestCaseJ4 {
+  
+  private static final String RANK_1 = "rank_1";
+  private static final String RANK_2 = "rank_2";
+
+  @BeforeClass
+  public static void beforeClass() throws Exception {
+    initCore("solrconfig-minimal.xml","schema-rank-fields.xml");
+  }
+  
+  @Override
+  public void setUp() throws Exception {
+    clearIndex();
+    assertU(commit());
+    super.setUp();
+  }
+  
+  public void testInternalFieldName() {
+    assertEquals("RankField.INTERNAL_RANK_FIELD_NAME changed in an incompatible way",
+        "_rank_", RankField.INTERNAL_RANK_FIELD_NAME);
+  }
+
+  public void testBasic() {
+    assertNotNull(h.getCore().getLatestSchema().getFieldOrNull(RANK_1));
+    assertEquals(RankField.class, h.getCore().getLatestSchema().getField(RANK_1).getType().getClass());
+  }
+  
+  public void testBadFormat() {
+    ignoreException("Expecting float");
+    assertFailedU(adoc(
+        "id", "1",
+        RANK_1, "foo"
+        ));
+
+    assertFailedU(adoc(
+        "id", "1",
+        RANK_1, "1.2.3"
+        ));
+    
+    unIgnoreException("Expecting float");
+    
+    ignoreException("must be finite");
+    assertFailedU(adoc(
+        "id", "1",
+        RANK_1, Float.toString(Float.POSITIVE_INFINITY)
+        ));
+
+    assertFailedU(adoc(
+        "id", "1",
+        RANK_1, Float.toString(Float.NEGATIVE_INFINITY)
+        ));
+    
+    assertFailedU(adoc(
+        "id", "1",
+        RANK_1, Float.toString(Float.NaN)
+        ));
+    
+    unIgnoreException("must be finite");
+    
+    ignoreException("must be a positive");
+    assertFailedU(adoc(
+        "id", "1",
+        RANK_1, Float.toString(-0.0f)
+        ));
+
+    assertFailedU(adoc(
+        "id", "1",
+        RANK_1, Float.toString(-1f)
+        ));
+
+    assertFailedU(adoc(
+        "id", "1",
+        RANK_1, Float.toString(0.0f)
+        ));
+    unIgnoreException("must be a positive");
+  }
+  
+  public void testAddRandom() {
+    for (int i = 0 ; i < random().nextInt(TEST_NIGHTLY ? 10000 : 100); i++) {
+      assertU(adoc(
+          "id", String.valueOf(i),
+          RANK_1, Float.toString(random().nextFloat())
+          ));
+    }
+    assertU(commit());
+  }
+  
+  public void testSkipEmpty() {
+    assertU(adoc(
+        "id", "1",
+        RANK_1, ""
+        ));
+  }
+  
+  public void testBasicAdd() throws IOException {
+    assertU(adoc(
+        "id", "testBasicAdd",
+        RANK_1, "1"
+        ));
+    assertU(commit());
+    //assert that the document made it in
+    assertQ(req("q", "id:testBasicAdd"), "//*[@numFound='1']");
+    h.getCore().withSearcher((searcher) -> {
+      LeafReader reader = searcher.getIndexReader().getContext().leaves().get(0).reader();
+      // assert that the field made it in
+      assertNotNull(reader.getFieldInfos().fieldInfo(RankField.INTERNAL_RANK_FIELD_NAME));
+      // assert that the feature made it in
+      assertTrue(reader.terms(RankField.INTERNAL_RANK_FIELD_NAME).iterator().seekExact(new BytesRef(RANK_1.getBytes(StandardCharsets.UTF_8))));
+      return null;
+    });
+  }
+  
+  public void testMultipleRankFields() throws IOException {
+    assertU(adoc(
+        "id", "testMultiValueAdd",
+        RANK_1, "1",
+        RANK_2, "2"
+        ));
+    assertU(commit());
+    //assert that the document made it in
+    assertQ(req("q", "id:testMultiValueAdd"), "//*[@numFound='1']");
+    h.getCore().withSearcher((searcher) -> {
+      LeafReader reader = searcher.getIndexReader().getContext().leaves().get(0).reader();
+      // assert that the field made it in
+      assertNotNull(reader.getFieldInfos().fieldInfo(RankField.INTERNAL_RANK_FIELD_NAME));
+      // assert that the features made it in
+      assertTrue(reader.terms(RankField.INTERNAL_RANK_FIELD_NAME).iterator().seekExact(new BytesRef(RANK_2.getBytes(StandardCharsets.UTF_8))));
+      assertTrue(reader.terms(RankField.INTERNAL_RANK_FIELD_NAME).iterator().seekExact(new BytesRef(RANK_1.getBytes(StandardCharsets.UTF_8))));
+      return null;
+    });
+  }
+  
+  public void testSortFails() throws IOException {
+    assertU(adoc(
+        "id", "testSortFails",
+        RANK_1, "1"
+        ));
+    assertU(commit());
+    assertQEx("Can't sort on rank field", req(
+        "q", "id:testSortFails",
+        "sort", RANK_1 + " desc"), 400);
+  }
+  
+  @Ignore("We currently don't fail these kinds of requests with other field types")
+  public void testFacetFails() throws IOException {
+    assertU(adoc(
+        "id", "testFacetFails",
+        RANK_1, "1"
+        ));
+    assertU(commit());
+    assertQEx("Can't facet on rank field", req(
+        "q", "id:testFacetFails",
+        "facet", "true",
+        "facet.field", RANK_1), 400);
+  }
+  
+  public void testTermQuery() throws IOException {
+    assertU(adoc(
+        "id", "testTermQuery",
+        RANK_1, "1",
+        RANK_2, "1"
+        ));
+    assertU(adoc(
+        "id", "testTermQuery2",
+        RANK_1, "1"
+        ));
+    assertU(commit());
+    assertQ(req("q", RANK_1 + ":*"), "//*[@numFound='2']");
+    assertQ(req("q", RANK_1 + ":[* TO *]"), "//*[@numFound='2']");
+    assertQ(req("q", RANK_2 + ":*"), "//*[@numFound='1']");
+    assertQ(req("q", RANK_2 + ":[* TO *]"), "//*[@numFound='1']");
+    
+    assertQEx("Term queries not supported", req("q", RANK_1 + ":1"), 400);
+    assertQEx("Range queries not supported", req("q", RANK_1 + ":[1 TO 10]"), 400);
+  }
+  
+  
+  public void testResponseQuery() throws IOException {
+    assertU(adoc(
+        "id", "testResponseQuery",
+        RANK_1, "1"
+        ));
+    assertU(commit());
+    // Ignore requests to retrieve rank
+    assertQ(req("q", RANK_1 + ":*",
+        "fl", "id," + RANK_1),
+        "//*[@numFound='1']",
+        "count(//result/doc[1]/str)=1");
+  }
+  
+  public void testRankQParserQuery() throws IOException {
+    assertU(adoc(
+        "id", "1",
+        "str_field", "foo",
+        RANK_1, "1",
+        RANK_2, "2"
+        ));
+    assertU(adoc(
+        "id", "2",
+        "str_field", "foo",
+        RANK_1, "2",
+        RANK_2, "1"
+        ));
+    assertU(commit());
+    assertQ(req("q", "str_field:foo _query_:{!rank f='" + RANK_1 + "' function='log' scalingFactor='1'}"),
+        "//*[@numFound='2']",
+        "//result/doc[1]/str[@name='id'][.='2']",
+        "//result/doc[2]/str[@name='id'][.='1']");
+    
+    assertQ(req("q", "str_field:foo _query_:{!rank f='" + RANK_2 + "' function='log' scalingFactor='1'}"),
+        "//*[@numFound='2']",
+        "//result/doc[1]/str[@name='id'][.='1']",
+        "//result/doc[2]/str[@name='id'][.='2']");
+    
+    assertQ(req("q", "foo",
+        "defType", "dismax",
+        "qf", "str_field^10",
+        "bq", "{!rank f='" + RANK_1 + "' function='log' scalingFactor='1'}"
+        ),
+        "//*[@numFound='2']",
+        "//result/doc[1]/str[@name='id'][.='2']",
+        "//result/doc[2]/str[@name='id'][.='1']");
+    
+    assertQ(req("q", "foo",
+        "defType", "dismax",
+        "qf", "str_field^10",
+        "bq", "{!rank f='" + RANK_2 + "' function='log' scalingFactor='1'}"
+        ),
+        "//*[@numFound='2']",
+        "//result/doc[1]/str[@name='id'][.='1']",
+        "//result/doc[2]/str[@name='id'][.='2']");
+  }
+

Review comment:
       If I add `"fl", "*,score,rank_1,rank_2",` we won't retrieve the value back. I think it's fine not to throw an error or anything right?




----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



---------------------------------------------------------------------
To unsubscribe, e-mail: issues-unsubscribe@lucene.apache.org
For additional commands, e-mail: issues-help@lucene.apache.org


[GitHub] [lucene-solr] vthacker commented on a change in pull request #1620: SOLR-14590 : Add support for Lucene's FeatureField in Solr

Posted by GitBox <gi...@apache.org>.
vthacker commented on a change in pull request #1620:
URL: https://github.com/apache/lucene-solr/pull/1620#discussion_r447419709



##########
File path: solr/core/src/test/org/apache/solr/schema/RankFieldTest.java
##########
@@ -0,0 +1,261 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.solr.schema;
+
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+
+import org.apache.lucene.index.LeafReader;
+import org.apache.lucene.util.BytesRef;
+import org.apache.solr.SolrTestCaseJ4;
+import org.junit.BeforeClass;
+import org.junit.Ignore;
+
+public class RankFieldTest extends SolrTestCaseJ4 {
+  
+  private static final String RANK_1 = "rank_1";
+  private static final String RANK_2 = "rank_2";
+
+  @BeforeClass
+  public static void beforeClass() throws Exception {
+    initCore("solrconfig-minimal.xml","schema-rank-fields.xml");
+  }
+  
+  @Override
+  public void setUp() throws Exception {
+    clearIndex();
+    assertU(commit());
+    super.setUp();
+  }
+  
+  public void testInternalFieldName() {
+    assertEquals("RankField.INTERNAL_RANK_FIELD_NAME changed in an incompatible way",
+        "_rank_", RankField.INTERNAL_RANK_FIELD_NAME);
+  }
+
+  public void testBasic() {
+    assertNotNull(h.getCore().getLatestSchema().getFieldOrNull(RANK_1));
+    assertEquals(RankField.class, h.getCore().getLatestSchema().getField(RANK_1).getType().getClass());
+  }
+  
+  public void testBadFormat() {
+    ignoreException("Expecting float");
+    assertFailedU(adoc(
+        "id", "1",
+        RANK_1, "foo"
+        ));
+
+    assertFailedU(adoc(
+        "id", "1",
+        RANK_1, "1.2.3"
+        ));
+    
+    unIgnoreException("Expecting float");
+    
+    ignoreException("must be finite");
+    assertFailedU(adoc(
+        "id", "1",
+        RANK_1, Float.toString(Float.POSITIVE_INFINITY)
+        ));
+
+    assertFailedU(adoc(
+        "id", "1",
+        RANK_1, Float.toString(Float.NEGATIVE_INFINITY)
+        ));
+    
+    assertFailedU(adoc(
+        "id", "1",
+        RANK_1, Float.toString(Float.NaN)
+        ));
+    
+    unIgnoreException("must be finite");
+    
+    ignoreException("must be a positive");
+    assertFailedU(adoc(
+        "id", "1",
+        RANK_1, Float.toString(-0.0f)
+        ));
+
+    assertFailedU(adoc(
+        "id", "1",
+        RANK_1, Float.toString(-1f)
+        ));
+
+    assertFailedU(adoc(
+        "id", "1",
+        RANK_1, Float.toString(0.0f)
+        ));
+    unIgnoreException("must be a positive");
+  }
+  
+  public void testAddRandom() {
+    for (int i = 0 ; i < random().nextInt(TEST_NIGHTLY ? 10000 : 100); i++) {
+      assertU(adoc(
+          "id", String.valueOf(i),
+          RANK_1, Float.toString(random().nextFloat())
+          ));
+    }
+    assertU(commit());
+  }
+  
+  public void testSkipEmpty() {
+    assertU(adoc(
+        "id", "1",
+        RANK_1, ""
+        ));
+  }
+  
+  public void testBasicAdd() throws IOException {
+    assertU(adoc(
+        "id", "testBasicAdd",
+        RANK_1, "1"
+        ));
+    assertU(commit());
+    //assert that the document made it in
+    assertQ(req("q", "id:testBasicAdd"), "//*[@numFound='1']");
+    h.getCore().withSearcher((searcher) -> {
+      LeafReader reader = searcher.getIndexReader().getContext().leaves().get(0).reader();
+      // assert that the field made it in
+      assertNotNull(reader.getFieldInfos().fieldInfo(RankField.INTERNAL_RANK_FIELD_NAME));
+      // assert that the feature made it in
+      assertTrue(reader.terms(RankField.INTERNAL_RANK_FIELD_NAME).iterator().seekExact(new BytesRef(RANK_1.getBytes(StandardCharsets.UTF_8))));
+      return null;
+    });
+  }
+  
+  public void testMultipleRankFields() throws IOException {
+    assertU(adoc(
+        "id", "testMultiValueAdd",
+        RANK_1, "1",
+        RANK_2, "2"
+        ));
+    assertU(commit());
+    //assert that the document made it in
+    assertQ(req("q", "id:testMultiValueAdd"), "//*[@numFound='1']");
+    h.getCore().withSearcher((searcher) -> {
+      LeafReader reader = searcher.getIndexReader().getContext().leaves().get(0).reader();
+      // assert that the field made it in
+      assertNotNull(reader.getFieldInfos().fieldInfo(RankField.INTERNAL_RANK_FIELD_NAME));
+      // assert that the features made it in
+      assertTrue(reader.terms(RankField.INTERNAL_RANK_FIELD_NAME).iterator().seekExact(new BytesRef(RANK_2.getBytes(StandardCharsets.UTF_8))));
+      assertTrue(reader.terms(RankField.INTERNAL_RANK_FIELD_NAME).iterator().seekExact(new BytesRef(RANK_1.getBytes(StandardCharsets.UTF_8))));
+      return null;
+    });
+  }
+  
+  public void testSortFails() throws IOException {
+    assertU(adoc(
+        "id", "testSortFails",
+        RANK_1, "1"
+        ));
+    assertU(commit());
+    assertQEx("Can't sort on rank field", req(
+        "q", "id:testSortFails",
+        "sort", RANK_1 + " desc"), 400);
+  }
+  
+  @Ignore("We currently don't fail these kinds of requests with other field types")
+  public void testFacetFails() throws IOException {
+    assertU(adoc(
+        "id", "testFacetFails",
+        RANK_1, "1"
+        ));
+    assertU(commit());
+    assertQEx("Can't facet on rank field", req(
+        "q", "id:testFacetFails",
+        "facet", "true",
+        "facet.field", RANK_1), 400);
+  }
+  
+  public void testTermQuery() throws IOException {
+    assertU(adoc(
+        "id", "testTermQuery",
+        RANK_1, "1",
+        RANK_2, "1"
+        ));
+    assertU(adoc(
+        "id", "testTermQuery2",
+        RANK_1, "1"
+        ));
+    assertU(commit());
+    assertQ(req("q", RANK_1 + ":*"), "//*[@numFound='2']");
+    assertQ(req("q", RANK_1 + ":[* TO *]"), "//*[@numFound='2']");
+    assertQ(req("q", RANK_2 + ":*"), "//*[@numFound='1']");
+    assertQ(req("q", RANK_2 + ":[* TO *]"), "//*[@numFound='1']");
+    
+    assertQEx("Term queries not supported", req("q", RANK_1 + ":1"), 400);
+    assertQEx("Range queries not supported", req("q", RANK_1 + ":[1 TO 10]"), 400);
+  }
+  
+  
+  public void testResponseQuery() throws IOException {
+    assertU(adoc(
+        "id", "testResponseQuery",
+        RANK_1, "1"
+        ));
+    assertU(commit());
+    // Ignore requests to retrieve rank
+    assertQ(req("q", RANK_1 + ":*",
+        "fl", "id," + RANK_1),
+        "//*[@numFound='1']",
+        "count(//result/doc[1]/str)=1");
+  }
+  
+  public void testRankQParserQuery() throws IOException {
+    assertU(adoc(
+        "id", "1",
+        "str_field", "foo",
+        RANK_1, "1",
+        RANK_2, "2"
+        ));
+    assertU(adoc(
+        "id", "2",
+        "str_field", "foo",
+        RANK_1, "2",
+        RANK_2, "1"
+        ));
+    assertU(commit());
+    assertQ(req("q", "str_field:foo _query_:{!rank f='" + RANK_1 + "' function='log' scalingFactor='1'}"),
+        "//*[@numFound='2']",
+        "//result/doc[1]/str[@name='id'][.='2']",
+        "//result/doc[2]/str[@name='id'][.='1']");
+    
+    assertQ(req("q", "str_field:foo _query_:{!rank f='" + RANK_2 + "' function='log' scalingFactor='1'}"),
+        "//*[@numFound='2']",
+        "//result/doc[1]/str[@name='id'][.='1']",
+        "//result/doc[2]/str[@name='id'][.='2']");
+    
+    assertQ(req("q", "foo",
+        "defType", "dismax",
+        "qf", "str_field^10",
+        "bq", "{!rank f='" + RANK_1 + "' function='log' scalingFactor='1'}"
+        ),
+        "//*[@numFound='2']",
+        "//result/doc[1]/str[@name='id'][.='2']",
+        "//result/doc[2]/str[@name='id'][.='1']");
+    
+    assertQ(req("q", "foo",
+        "defType", "dismax",
+        "qf", "str_field^10",
+        "bq", "{!rank f='" + RANK_2 + "' function='log' scalingFactor='1'}"
+        ),
+        "//*[@numFound='2']",
+        "//result/doc[1]/str[@name='id'][.='1']",
+        "//result/doc[2]/str[@name='id'][.='2']");
+  }

Review comment:
       Also I was curious to see if `debugQuery=true` does the right thing ( it does! )
   
   ```
   
   
   <?xml version="1.0" encoding="UTF-8"?>
   <response>
      <lst name="responseHeader">
         <int name="status">0</int>
         <int name="QTime">161</int>
         <lst name="params">
            <str name="q">foo</str>
            <str name="defType">dismax</str>
            <str name="qf">str_field^10</str>
            <str name="fl">*,score,rank_1,rank_2</str>
            <str name="wt">xml</str>
            <str name="debugQuery">true</str>
            <str name="bq">{!rank f='rank_2' function='log' scalingFactor='1'}</str>
         </lst>
      </lst>
      <result name="response" numFound="2" start="0" maxScore="1.9273467" numFoundExact="true">
         <doc>
            <str name="id">1</str>
            <str name="str_field">foo</str>
            <float name="score">1.9273467</float>
         </doc>
         <doc>
            <str name="id">2</str>
            <str name="str_field">foo</str>
            <float name="score">1.5218816</float>
         </doc>
      </result>
      <lst name="debug">
         <str name="rawquerystring">foo</str>
         <str name="querystring">foo</str>
         <str name="parsedquery">+DisjunctionMaxQuery(((str_field:foo)^10.0)) () FeatureQuery(FeatureQuery(field=_rank_, feature=rank_2, function=LogFunction(scalingFactor=1.0)))</str>
         <str name="parsedquery_toString">+((str_field:foo)^10.0) () FeatureQuery(field=_rank_, feature=rank_2, function=LogFunction(scalingFactor=1.0))</str>
         <lst name="explain">
            <str>1.9273467 = sum of:
     0.82873434 = weight(str_field:foo in 0) [SchemaSimilarity], result of:
       0.82873434 = score(freq=1.0), computed as boost * idf * tf from:
         10.0 = boost
         0.18232156 = idf, computed as log(1 + (N - n + 0.5) / (n + 0.5)) from:
           2 = n, number of documents containing term
           2 = N, total number of documents with field
         0.45454544 = tf, computed as freq / (freq + k1 * (1 - b + b * dl / avgdl)) from:
           1.0 = freq, occurrences of term within document
           1.2 = k1, term saturation parameter
           0.75 = b, length normalization parameter
           1.0 = dl, length of field
           1.0 = avgdl, average length of field
     1.0986123 = Log function on the _rank_ field for the rank_2 feature, computed as w * log(a + S) from:
       1.0 = w, weight of this function
       1.0 = a, scaling factor
       2.0 = S, feature value</str>
            <str>1.5218816 = sum of:
     0.82873434 = weight(str_field:foo in 1) [SchemaSimilarity], result of:
       0.82873434 = score(freq=1.0), computed as boost * idf * tf from:
         10.0 = boost
         0.18232156 = idf, computed as log(1 + (N - n + 0.5) / (n + 0.5)) from:
           2 = n, number of documents containing term
           2 = N, total number of documents with field
         0.45454544 = tf, computed as freq / (freq + k1 * (1 - b + b * dl / avgdl)) from:
           1.0 = freq, occurrences of term within document
           1.2 = k1, term saturation parameter
           0.75 = b, length normalization parameter
           1.0 = dl, length of field
           1.0 = avgdl, average length of field
     0.6931472 = Log function on the _rank_ field for the rank_2 feature, computed as w * log(a + S) from:
       1.0 = w, weight of this function
       1.0 = a, scaling factor
       1.0 = S, feature value</str>
         </lst>
         <str name="QParser">DisMaxQParser</str>
         <null name="altquerystring" />
         <arr name="boost_queries">
            <str>{!rank f='rank_2' function='log' scalingFactor='1'}</str>
         </arr>
         <arr name="parsed_boost_queries">
            <str>FeatureQuery(FeatureQuery(field=_rank_, feature=rank_2, function=LogFunction(scalingFactor=1.0)))</str>
         </arr>
         <null name="boostfuncs" />
         <lst name="timing">
            <double name="time">160.0</double>
            <lst name="prepare">
               <double name="time">1.0</double>
               <lst name="query">
                  <double name="time">1.0</double>
               </lst>
               <lst name="facet">
                  <double name="time">0.0</double>
               </lst>
               <lst name="facet_module">
                  <double name="time">0.0</double>
               </lst>
               <lst name="mlt">
                  <double name="time">0.0</double>
               </lst>
               <lst name="highlight">
                  <double name="time">0.0</double>
               </lst>
               <lst name="stats">
                  <double name="time">0.0</double>
               </lst>
               <lst name="expand">
                  <double name="time">0.0</double>
               </lst>
               <lst name="terms">
                  <double name="time">0.0</double>
               </lst>
               <lst name="debug">
                  <double name="time">0.0</double>
               </lst>
            </lst>
            <lst name="process">
               <double name="time">155.0</double>
               <lst name="query">
                  <double name="time">3.0</double>
               </lst>
               <lst name="facet">
                  <double name="time">0.0</double>
               </lst>
               <lst name="facet_module">
                  <double name="time">0.0</double>
               </lst>
               <lst name="mlt">
                  <double name="time">0.0</double>
               </lst>
               <lst name="highlight">
                  <double name="time">0.0</double>
               </lst>
               <lst name="stats">
                  <double name="time">0.0</double>
               </lst>
               <lst name="expand">
                  <double name="time">0.0</double>
               </lst>
               <lst name="terms">
                  <double name="time">0.0</double>
               </lst>
               <lst name="debug">
                  <double name="time">152.0</double>
               </lst>
            </lst>
         </lst>
      </lst>
   </response>
   ```




----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



---------------------------------------------------------------------
To unsubscribe, e-mail: issues-unsubscribe@lucene.apache.org
For additional commands, e-mail: issues-help@lucene.apache.org


[GitHub] [lucene-solr] vthacker commented on a change in pull request #1620: SOLR-14590 : Alternative approach

Posted by GitBox <gi...@apache.org>.
vthacker commented on a change in pull request #1620:
URL: https://github.com/apache/lucene-solr/pull/1620#discussion_r446429171



##########
File path: solr/core/src/java/org/apache/solr/schema/RankField.java
##########
@@ -0,0 +1,92 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.solr.schema;
+
+import java.io.IOException;
+import java.util.Map;
+
+import org.apache.lucene.document.FeatureField;
+import org.apache.lucene.index.IndexableField;
+import org.apache.lucene.index.IndexableFieldType;
+import org.apache.lucene.index.Term;
+import org.apache.lucene.search.Query;
+import org.apache.lucene.search.SortField;
+import org.apache.lucene.search.TermQuery;
+import org.apache.solr.common.SolrException;
+import org.apache.solr.response.TextResponseWriter;
+import org.apache.solr.search.QParser;
+import org.apache.solr.uninverting.UninvertingReader.Type;
+
+public class RankField extends FieldType {
+  
+  public static final String INTERNAL_RANK_FIELD_NAME = "_internal_rank_field";
+
+  @Override
+  public Type getUninversionType(SchemaField sf) {
+    throw null;
+  }
+
+  @Override
+  public void write(TextResponseWriter writer, String name, IndexableField f) throws IOException {
+  }
+  
+  @Override
+  protected void init(IndexSchema schema, Map<String,String> args) {
+    super.init(schema, args);
+    if (schema.getFieldOrNull(INTERNAL_RANK_FIELD_NAME) != null) {
+      throw new SolrException(SolrException.ErrorCode.SERVER_ERROR, "A field named \"" + INTERNAL_RANK_FIELD_NAME + "\" can't be defined in the schema");
+    }
+    for (int prop:new int[] {STORED, DOC_VALUES, OMIT_TF_POSITIONS, SORT_MISSING_FIRST, SORT_MISSING_LAST}) {
+      if ((trueProperties & prop) != 0) {
+        throw new SolrException(SolrException.ErrorCode.SERVER_ERROR, "Property \"" + getPropertyName(prop) + "\" can't be set to true in RankFields");
+      }
+    }
+    for (int prop:new int[] {UNINVERTIBLE, INDEXED, MULTIVALUED}) {
+      if ((falseProperties & prop) != 0) {
+        throw new SolrException(SolrException.ErrorCode.SERVER_ERROR, "Property \"" + getPropertyName(prop) + "\" can't be set to false in RankFields");
+      }
+    }
+    properties &= ~(UNINVERTIBLE | STORED | DOC_VALUES);
+    
+  }
+
+  @Override
+  protected IndexableField createField(String name, String val, IndexableFieldType type) {
+    if (val == null || val.isEmpty()) {
+      return null;
+    }
+    float featureValue;
+    try {
+      featureValue = Float.parseFloat(val);
+    } catch (NumberFormatException nfe) {
+      throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, "Error while creating field '" + name + "' from value '" + val + "'. Expecting float.", nfe);
+    }
+    return new FeatureField(INTERNAL_RANK_FIELD_NAME, name, featureValue);
+  }
+
+  @Override
+  public Query getFieldQuery(QParser parser, SchemaField field, String externalVal) {

Review comment:
       I think so? Essentially this is an exists query right?
   
   We can be safe and not support this for now? 
   
   Thinking aloud on another option - What if we rewrite ( like how you have it right now ) when the value is `*` and throw an exception otherwise?




----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



---------------------------------------------------------------------
To unsubscribe, e-mail: issues-unsubscribe@lucene.apache.org
For additional commands, e-mail: issues-help@lucene.apache.org


[GitHub] [lucene-solr] vthacker commented on a change in pull request #1620: SOLR-14590 : Add support for Lucene's FeatureField in Solr

Posted by GitBox <gi...@apache.org>.
vthacker commented on a change in pull request #1620:
URL: https://github.com/apache/lucene-solr/pull/1620#discussion_r447411333



##########
File path: solr/core/src/java/org/apache/solr/schema/RankField.java
##########
@@ -0,0 +1,92 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.solr.schema;
+
+import java.io.IOException;
+import java.util.Map;
+
+import org.apache.lucene.document.FeatureField;
+import org.apache.lucene.index.IndexableField;
+import org.apache.lucene.index.IndexableFieldType;
+import org.apache.lucene.index.Term;
+import org.apache.lucene.search.Query;
+import org.apache.lucene.search.SortField;
+import org.apache.lucene.search.TermQuery;
+import org.apache.solr.common.SolrException;
+import org.apache.solr.response.TextResponseWriter;
+import org.apache.solr.search.QParser;
+import org.apache.solr.uninverting.UninvertingReader.Type;
+
+public class RankField extends FieldType {
+  
+  public static final String INTERNAL_RANK_FIELD_NAME = "_internal_rank_field";
+
+  @Override
+  public Type getUninversionType(SchemaField sf) {
+    throw null;
+  }
+
+  @Override
+  public void write(TextResponseWriter writer, String name, IndexableField f) throws IOException {
+  }
+  
+  @Override
+  protected void init(IndexSchema schema, Map<String,String> args) {
+    super.init(schema, args);
+    if (schema.getFieldOrNull(INTERNAL_RANK_FIELD_NAME) != null) {
+      throw new SolrException(SolrException.ErrorCode.SERVER_ERROR, "A field named \"" + INTERNAL_RANK_FIELD_NAME + "\" can't be defined in the schema");
+    }
+    for (int prop:new int[] {STORED, DOC_VALUES, OMIT_TF_POSITIONS, SORT_MISSING_FIRST, SORT_MISSING_LAST}) {
+      if ((trueProperties & prop) != 0) {
+        throw new SolrException(SolrException.ErrorCode.SERVER_ERROR, "Property \"" + getPropertyName(prop) + "\" can't be set to true in RankFields");
+      }
+    }
+    for (int prop:new int[] {UNINVERTIBLE, INDEXED, MULTIVALUED}) {
+      if ((falseProperties & prop) != 0) {
+        throw new SolrException(SolrException.ErrorCode.SERVER_ERROR, "Property \"" + getPropertyName(prop) + "\" can't be set to false in RankFields");
+      }
+    }
+    properties &= ~(UNINVERTIBLE | STORED | DOC_VALUES);
+    
+  }
+
+  @Override
+  protected IndexableField createField(String name, String val, IndexableFieldType type) {
+    if (val == null || val.isEmpty()) {
+      return null;
+    }
+    float featureValue;
+    try {
+      featureValue = Float.parseFloat(val);
+    } catch (NumberFormatException nfe) {
+      throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, "Error while creating field '" + name + "' from value '" + val + "'. Expecting float.", nfe);
+    }
+    return new FeatureField(INTERNAL_RANK_FIELD_NAME, name, featureValue);
+  }
+
+  @Override
+  public Query getFieldQuery(QParser parser, SchemaField field, String externalVal) {

Review comment:
       > Thinking aloud on another option - What if we rewrite ( like how you have it right now ) when the value is * and throw an exception otherwise?
   
   Nice! we added it to `getExistenceQuery` and in `getFieldQuery` we throw an exception!




----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



---------------------------------------------------------------------
To unsubscribe, e-mail: issues-unsubscribe@lucene.apache.org
For additional commands, e-mail: issues-help@lucene.apache.org


[GitHub] [lucene-solr] vthacker commented on a change in pull request #1620: SOLR-14590 : Add support for Lucene's FeatureField in Solr

Posted by GitBox <gi...@apache.org>.
vthacker commented on a change in pull request #1620:
URL: https://github.com/apache/lucene-solr/pull/1620#discussion_r447410253



##########
File path: solr/core/src/java/org/apache/solr/schema/RankField.java
##########
@@ -0,0 +1,140 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.solr.schema;
+
+import java.io.IOException;
+import java.util.Map;
+
+import org.apache.lucene.document.FeatureField;
+import org.apache.lucene.index.IndexableField;
+import org.apache.lucene.index.IndexableFieldType;
+import org.apache.lucene.index.Term;
+import org.apache.lucene.search.Query;
+import org.apache.lucene.search.SortField;
+import org.apache.lucene.search.TermQuery;
+import org.apache.solr.common.SolrException;
+import org.apache.solr.response.TextResponseWriter;
+import org.apache.solr.search.QParser;
+import org.apache.solr.search.RankQParserPlugin;
+import org.apache.solr.uninverting.UninvertingReader.Type;
+
+/**
+ * <p>
+ * {@code RankField}s can be used to store scoring factors to improve document ranking. They should be used
+ * in combination with {@link RankQParserPlugin}. To use:
+ * </p>
+ * <p>
+ * Define the {@code RankField} {@code fieldType} in your schema:
+ * </p>
+ * <pre class="prettyprint">
+ * &lt;fieldType name="rank" class="solr.RankField" /&gt;
+ * </pre>
+ * <p>
+ * Add fields to the schema, i.e.:
+ * </p>
+ * <pre class="prettyprint">
+ * &lt;field name="rank_1" type="rank" /&gt;

Review comment:
       small nit: something like `document_length_boost` might be a better example to help a user realize how they can leverage this feature?




----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



---------------------------------------------------------------------
To unsubscribe, e-mail: issues-unsubscribe@lucene.apache.org
For additional commands, e-mail: issues-help@lucene.apache.org