DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Refcards Trend Reports
Events Video Library
Over 2 million developers have joined DZone. Join Today! Thanks for visiting DZone today,
Edit Profile Manage Email Subscriptions Moderation Admin Console How to Post to DZone Article Submission Guidelines
View Profile
Sign Out
Refcards
Trend Reports
Events
View Events Video Library
Zones
Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks

Integrating PostgreSQL Databases with ANF: Join this workshop to learn how to create a PostgreSQL server using Instaclustr’s managed service

Mobile Database Essentials: Assess data needs, storage requirements, and more when leveraging databases for cloud and edge applications.

Monitoring and Observability for LLMs: Datadog and Google Cloud discuss how to achieve optimal AI model performance.

Automated Testing: The latest on architecture, TDD, and the benefits of AI and low-code tools.

Related

  • A Better Web3 Experience: Account Abstraction From Flow (Part 2)
  • Training a Handwritten Digits Classifier in Pytorch With Apache Cassandra Database
  • Mastering Persistence: Why the Persistence Layer Is Crucial for Modern Java Applications
  • .NET Performance Optimization Techniques for Expert Developers

Trending

  • Auditing Spring Boot Using JPA, Hibernate, and Spring Data JPA
  • REST vs. Message Brokers: Choosing the Right Communication
  • Getting Started With Prometheus Workshop: Instrumenting Applications
  • How To Validate Archives and Identify Invalid Documents in Java
  1. DZone
  2. Data Engineering
  3. Databases
  4. How to write a custom Solr FunctionQuery

How to write a custom Solr FunctionQuery

Kelvin Tan user avatar by
Kelvin Tan
·
Feb. 02, 11 · News
Like (0)
Save
Tweet
Share
23.70K Views

Join the DZone community and get the full member experience.

Join For Free

Solr FunctionQueries allow you to modify the ranking of a search query in Solr by applying functions to the results.

There are a list of out-of-box FunctionQueries available here: http://wiki.apache.org/solr/FunctionQuery

In order to write a custom Solr FunctionQuery, you'll need to do 2 things:

1. Subclass org.apache.solr.search.ValueSourceParser. Here's a stub ValueSourceParser.

public class MyValueSourceParser extends ValueSourceParser {
  public void init(NamedList namedList) {
  }

  public ValueSource parse(FunctionQParser fqp) throws ParseException {
    return new MyValueSource();
  }
}

2. In solrconfig.xml, register your new ValueSourceParser directly under the <config> tag

<valueSourceParser name="myfunc" class="com.mycompany.MyValueSourceParser" />

3. Subclass org.apache.solr.search.ValueSource and instantiate it in your ValueSourceParser.parse() method.

Lets take a look at 2 ValueSource implementations to see what they do, starting with the simplest:

org.apache.solr.search.function.ConstValueSource

Example SolrQuerySyntax: _val_:1.5

It simply returns a float value.

public class ConstValueSource extends ValueSource {
  final float constant;

  public ConstValueSource(float constant) {
    this.constant = constant;
  }

  public DocValues getValues(Map context, IndexReader reader) throws IOException {
    return new DocValues() {
      public float floatVal(int doc) {
        return constant;
      }
      public int intVal(int doc) {
        return (int)floatVal(doc);
      }
      public long longVal(int doc) {
        return (long)floatVal(doc);
      }
      public double doubleVal(int doc) {
        return (double)floatVal(doc);
      }
      public String strVal(int doc) {
        return Float.toString(floatVal(doc));
      }
      public String toString(int doc) {
        return description();
      }
    };
  }
// commented out some boilerplate stuff
}

As you can see, the important method is DocValues getValues(Map context, IndexReader reader). The gist of the method is return a DocValues object which returns a value given a document id.

org.apache.solr.search.function.OrdFieldSource

ord(myfield) returns the ordinal of the indexed field value within the indexed list of terms for that field in lucene index order (lexicographically ordered by unicode value), starting at 1. In other words, for a given field, all values are ordered lexicographically; this function then returns the offset of a particular value in that ordering.


Example SolrQuerySyntax: _val_:"ord(myIndexedField)"

public class OrdFieldSource extends ValueSource {
  protected String field;

  public OrdFieldSource(String field) {
    this.field = field;
  }
  public DocValues getValues(Map context, IndexReader reader) throws IOException {
    return new StringIndexDocValues(this, reader, field) {
      protected String toTerm(String readableValue) {
        return readableValue;
      }
     
      public float floatVal(int doc) {
        return (float)order[doc];
      }

      public int intVal(int doc) {
        return order[doc];
      }

      public long longVal(int doc) {
        return (long)order[doc];
      }

      public double doubleVal(int doc) {
        return (double)order[doc];
      }

      public String strVal(int doc) {
        // the string value of the ordinal, not the string itself
        return Integer.toString(order[doc]);
      }

      public String toString(int doc) {
        return description() + '=' + intVal(doc);
      }
    };
  }
}

OrdFieldSource is almost identical to ConstValueSource, the main differences being the returning of the order rather than a const value, and the use of StringIndexDocValues which is for obtaining the order of values.

Our own ValueSource

We now have a pretty good idea what a ValueSource subclass has to do:

return some value for a given doc id.

This can be based on the value of a field in the index (like OrdFieldSource), or nothing to do with the index at all (like ConstValueSource).

Here's one that performs the opposite of MaxFloatFunction/max() - MinFloatFunction/min():

public class MinFloatFunction extends ValueSource {
  protected final ValueSource source;
  protected final float fval;

  public MinFloatFunction(ValueSource source, float fval) {
    this.source = source;
    this.fval = fval;
  }
 
  public DocValues getValues(Map context, IndexReader reader) throws IOException {
    final DocValues vals =  source.getValues(context, reader);
    return new DocValues() {
      public float floatVal(int doc) {
    float v = vals.floatVal(doc);
        return v > fval ? fval : v;
      }
      public int intVal(int doc) {
        return (int)floatVal(doc);
      }
      public long longVal(int doc) {
        return (long)floatVal(doc);
      }
      public double doubleVal(int doc) {
        return (double)floatVal(doc);
      }
      public String strVal(int doc) {
        return Float.toString(floatVal(doc));
      }
      public String toString(int doc) {
    return "max(" + vals.toString(doc) + "," + fval + ")";
      }
    };
  }

  @Override
  public void createWeight(Map context, Searcher searcher) throws IOException {
    source.createWeight(context, searcher);
  }

// boilerplate methods omitted
}

And the corresponding ValueSourceParser:

public class MinValueSourceParser extends ValueSourceParser {
  public void init(NamedList namedList) {
  }

  public ValueSource parse(FunctionQParser fqp) throws ParseException {
        ValueSource source = fp.parseValueSource();
        float val = fp.parseFloat();
        return new MinFloatFunction(source,val);
  }
}

 

Database

Published at DZone with permission of Kelvin Tan. See the original article here.

Opinions expressed by DZone contributors are their own.

Related

  • A Better Web3 Experience: Account Abstraction From Flow (Part 2)
  • Training a Handwritten Digits Classifier in Pytorch With Apache Cassandra Database
  • Mastering Persistence: Why the Persistence Layer Is Crucial for Modern Java Applications
  • .NET Performance Optimization Techniques for Expert Developers

Comments

Partner Resources

X

ABOUT US

  • About DZone
  • Send feedback
  • Careers
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 3343 Perimeter Hill Drive
  • Suite 100
  • Nashville, TN 37211
  • support@dzone.com

Let's be friends: