Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add clienv-java module with ElastiknnNearestNeighborsQueryBuilder for running queries via Java REST client #260

Merged
merged 13 commits into from
Jun 26, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ subprojects {
Project api4s = project(':api4s')
Project benchmarks = project(':benchmarks')
Project clientElastic4s = project(':client-elastic4s')
Project clientJava = project(':client-java')
Project lucene = project(':lucene')
Project models = project(':models')
Project plugin = project(':plugin')
Expand Down Expand Up @@ -204,6 +205,16 @@ configure(clientElastic4s, List.of(
}
}))

configure(clientJava, List.of(
publishConfig("Java APIs for Elastiknn, intended for use with Elasticsearch REST clients", false),
{
dependencies {
implementation "org.elasticsearch:elasticsearch:${esVersion}"
}
}
))


configure(models, List.of(
publishConfig("Exact and approximate similarity models used in Elastiknn", false)))

Expand Down Expand Up @@ -266,6 +277,7 @@ configure(testing, List.of(scalaProjectConfig, {
dependencies {
implementation models
implementation clientElastic4s
implementation clientJava
implementation plugin
implementation lucene
implementation 'com.typesafe:config:1.4.0'
Expand All @@ -276,6 +288,7 @@ configure(testing, List.of(scalaProjectConfig, {
implementation "org.apache.lucene:lucene-codecs:${luceneVersion}"
implementation "org.apache.lucene:lucene-analyzers-common:${luceneVersion}"
implementation "org.elasticsearch:elasticsearch:${esVersion}"
implementation "org.elasticsearch.client:elasticsearch-rest-high-level-client:${esVersion}"
implementation "com.storm-enroute:scalameter_${scalaShortVersion}:0.19"
implementation "org.scalanlp:breeze_${scalaShortVersion}:1.0"
implementation "com.klibisz.futil:futil_${scalaShortVersion}:0.1.2"
Expand Down
2 changes: 1 addition & 1 deletion docs/Taskfile.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ tasks:
- install-bundler
cmds:
- bundle install
- bundle exec jekyll serve
- bundle exec jekyll serve --port 4001

compile:
desc: Compile docs into a static site.
Expand Down
29 changes: 26 additions & 3 deletions docs/pages/libraries.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,9 @@ This includes a low level client that roughly mirrors the [Scala client](/scala-
|:--|:--|
|Release|[![Python Release][Badge-Python-Release]][Link-Python-Release]|

## Java library with exact and approximate similarity models
## Java library with exact and approximate nearest neighbor search models

This library contains the exact and approximate similarity models used by Elastiknn.
This library contains the exact and approximate nearest neighbor search models used by Elastiknn.

**Install**

Expand Down Expand Up @@ -68,9 +68,27 @@ implementation 'com.klibisz.elastiknn:lucene:<version below>'
**Versions**

|:--|:--|
|Rekease|[![Lucene Release][Badge-Lucene-Release]][Link-Lucene-Release]|
|Release|[![Lucene Release][Badge-Lucene-Release]][Link-Lucene-Release]|
|Snapshot|[![Lucene Snapshot][Badge-Lucene-Snapshot]][Link-Lucene-Snapshot]|

## Java library with Elasticsearch query builder for Elastiknn queries

This library contains a custom [query builder](https://www.elastic.co/guide/en/elasticsearch/client/java-rest/current/java-rest-high-query-builders.html)
for defining Elastiknn queries in Java.

**Install**

In a Gradle project:

```groovy
implementation 'com.klibisz.elastiknn:client-java:<version below>'
```

**Versions**

|:--|:--|
|Release|[![Lucene Release][Badge-Java-Client-Release]][Link-Java-Client-Release]|
|Snapshot|[![Lucene Snapshot][Badge-Java-Client-Snapshot]][Link-Java-Client-Snapshot]|

## Scala client

Expand Down Expand Up @@ -142,6 +160,11 @@ libraryDependencies += "com.klibisz.elastiknn" %% "api4s" % <version below>
[Link-Lucene-Release]: https://search.maven.org/artifact/com.klibisz.elastiknn/lucene
[Link-Lucene-Snapshot]: https://oss.sonatype.org/#nexus-search;gav~com.klibisz.elastiknn~lucene~~~

[Badge-Java-Client-Release]: https://img.shields.io/nexus/r/com.klibisz.elastiknn/client-java?server=http%3A%2F%2Foss.sonatype.org&style=flat-square "lucene release"
[Badge-Java-Client-Snapshot]: https://img.shields.io/nexus/s/com.klibisz.elastiknn/client-java?server=http%3A%2F%2Foss.sonatype.org&style=flat-square "lucene snapshot"
[Link-Java-Client-Release]: https://search.maven.org/artifact/com.klibisz.elastiknn/client-java
[Link-Java-Client-Snapshot]: https://oss.sonatype.org/#nexus-search;gav~com.klibisz.elastiknn~client-java~~~

[Badge-Api4s-Release]: https://img.shields.io/nexus/r/com.klibisz.elastiknn/api4s_2.12?server=http%3A%2F%2Foss.sonatype.org&style=flat-square "api4s_2.12 release"
[Badge-Api4s-Snapshot]: https://img.shields.io/nexus/s/com.klibisz.elastiknn/api4s_2.12?server=http%3A%2F%2Foss.sonatype.org&style=flat-square "api4s_2.12 snapshot"
[Link-Api4s-Release]: https://search.maven.org/artifact/com.klibisz.elastiknn/api4s_2.12
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
package com.klibisz.elastiknn;

import com.klibisz.elastiknn.api4j.ElastiknnNearestNeighborsQuery;
import com.klibisz.elastiknn.api4j.Vector;
import org.apache.lucene.search.Query;
import org.elasticsearch.common.io.stream.StreamOutput;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.index.query.AbstractQueryBuilder;
import org.elasticsearch.index.query.SearchExecutionContext;

import java.io.IOException;
import java.util.Objects;

public class ElastiknnNearestNeighborsQueryBuilder extends AbstractQueryBuilder<ElastiknnNearestNeighborsQueryBuilder> {

private final ElastiknnNearestNeighborsQuery query;
private final String field;

public ElastiknnNearestNeighborsQueryBuilder(ElastiknnNearestNeighborsQuery query, String field) {
this.query = query;
this.field = field;
}

@Override
protected void doWriteTo(StreamOutput out) {
throw new UnsupportedOperationException("doWriteTo is not implemented");
}

@Override
protected void doXContent(XContentBuilder builder, Params params) throws IOException {
builder.startObject(getWriteableName());
builder.field("field", field);
builder.field("similarity", query.getSimilarity().toString());
if (query instanceof ElastiknnNearestNeighborsQuery.Exact) {
builder.field("model", "exact");
} else if (query instanceof ElastiknnNearestNeighborsQuery.AngularLsh) {
ElastiknnNearestNeighborsQuery.AngularLsh q = (ElastiknnNearestNeighborsQuery.AngularLsh) query;
builder.field("model", "lsh");
builder.field("candidates", q.getCandidates());
} else if (query instanceof ElastiknnNearestNeighborsQuery.L2Lsh) {
ElastiknnNearestNeighborsQuery.L2Lsh q = (ElastiknnNearestNeighborsQuery.L2Lsh) query;
builder.field("model", "lsh");
builder.field("candidates", q.getCandidates());
builder.field("probes", q.getProbes());
} else if (query instanceof ElastiknnNearestNeighborsQuery.PermutationLsh) {
ElastiknnNearestNeighborsQuery.PermutationLsh q = (ElastiknnNearestNeighborsQuery.PermutationLsh) query;
builder.field("model", "permutation_lsh");
builder.field("candidates", q.getCandidates());
} else {
throw new RuntimeException(String.format("Unexpected query type [%s]", query.getClass().toString()));
}
if (query.getVector() instanceof Vector.DenseFloat) {
Vector.DenseFloat dfv = (Vector.DenseFloat) query.getVector();
builder.field("vec", dfv.values);
} else if (query.getVector() instanceof Vector.SparseBool) {
Vector.SparseBool sbv = (Vector.SparseBool) query.getVector();
builder.startArray("vec");
builder.value(sbv.trueIndices);
builder.value(sbv.totalIndices);
builder.endArray();
} else {
throw new RuntimeException(String.format("Unexpected vector type [%s]", query.getVector().getClass().toString()));
}
builder.endObject();
}

@Override
protected Query doToQuery(SearchExecutionContext context) {
throw new UnsupportedOperationException("doToQuery is not implemented");
}

@Override
protected boolean doEquals(ElastiknnNearestNeighborsQueryBuilder other) {
return other != null && ((this == other) || (query.equals(other.query) && field.equals(other.field)));
}

@Override
protected int doHashCode() {
return Objects.hash(query, field);
}

@Override
public String getWriteableName() {
return "elastiknn_nearest_neighbors";
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
package com.klibisz.elastiknn.api4j;

import java.util.Objects;

public abstract class ElastiknnNearestNeighborsQuery {

private ElastiknnNearestNeighborsQuery() {}

public abstract Vector getVector();
public abstract Similarity getSimilarity();

public static final class Exact extends ElastiknnNearestNeighborsQuery {
private final Similarity similarity;
private final Vector vector;
public Exact(Vector vector, Similarity similarity) {
this.similarity = similarity;
this.vector = vector;
}

@Override
public Vector getVector() {
return vector;
}

@Override
public Similarity getSimilarity() {
return similarity;
}

@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Exact exact = (Exact) o;
return getSimilarity() == exact.getSimilarity() && Objects.equals(getVector(), exact.getVector());
}

@Override
public int hashCode() {
return Objects.hash(getSimilarity(), getVector());
}
}

public static final class AngularLsh extends ElastiknnNearestNeighborsQuery {
private final Vector vector;
private final Integer candidates;
public AngularLsh(Vector vector, Integer candidates) {
this.vector = vector;
this.candidates = candidates;
}

public Integer getCandidates() {
return candidates;
}

@Override
public Vector getVector() {
return vector;
}

@Override
public Similarity getSimilarity() {
return Similarity.ANGULAR;
}

@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
AngularLsh that = (AngularLsh) o;
return Objects.equals(getVector(), that.getVector()) && Objects.equals(getCandidates(), that.getCandidates()) && getSimilarity() == that.getSimilarity();
}

@Override
public int hashCode() {
return Objects.hash(getVector(), getCandidates(), getSimilarity());
}
}

public static final class L2Lsh extends ElastiknnNearestNeighborsQuery {
private final Vector.DenseFloat vector;
private final Integer candidates;
private final Integer probes;
public L2Lsh(Vector.DenseFloat vector, Integer candidates, Integer probes) {
this.vector = vector;
this.candidates = candidates;
this.probes = probes;
}

public Integer getProbes() {
return probes;
}

public Integer getCandidates() {
return candidates;
}

@Override
public Vector getVector() {
return vector;
}

@Override
public Similarity getSimilarity() {
return Similarity.L2;
}

@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
L2Lsh l2Lsh = (L2Lsh) o;
return Objects.equals(getVector(), l2Lsh.getVector()) && Objects.equals(getCandidates(), l2Lsh.getCandidates()) && Objects.equals(getProbes(), l2Lsh.getProbes()) && getSimilarity() == l2Lsh.getSimilarity();
}

@Override
public int hashCode() {
return Objects.hash(getVector(), getCandidates(), getProbes(), getSimilarity());
}
}

public final static class PermutationLsh extends ElastiknnNearestNeighborsQuery {
private final Vector.DenseFloat vector;
private final Similarity similarity;
private final Integer candidates;
public PermutationLsh(Vector.DenseFloat vector, Similarity similarity, Integer candidates) {
this.vector = vector;
this.similarity = similarity;
this.candidates = candidates;
}

public Integer getCandidates() {
return candidates;
}

@Override
public Vector getVector() {
return vector;
}

@Override
public Similarity getSimilarity() {
return similarity;
}

@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
PermutationLsh that = (PermutationLsh) o;
return Objects.equals(getVector(), that.getVector()) && getSimilarity() == that.getSimilarity() && Objects.equals(getCandidates(), that.getCandidates());
}

@Override
public int hashCode() {
return Objects.hash(getVector(), getSimilarity(), getCandidates());
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package com.klibisz.elastiknn.api4j;

public enum Similarity {
JACCARD,
HAMMING,
L1,
L2,
ANGULAR
}
Loading