Skip to content

Commit

Permalink
HSEARCH-5164 Introduce a new dialect to always pass the index_options…
Browse files Browse the repository at this point in the history
….type=hnsw
  • Loading branch information
marko-bekhta committed Jun 7, 2024
1 parent ad88854 commit 2e36d0e
Show file tree
Hide file tree
Showing 10 changed files with 153 additions and 20 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
import org.hibernate.search.backend.elasticsearch.ElasticsearchVersion;
import org.hibernate.search.backend.elasticsearch.dialect.model.impl.Elasticsearch7ModelDialect;
import org.hibernate.search.backend.elasticsearch.dialect.model.impl.Elasticsearch812ModelDialect;
import org.hibernate.search.backend.elasticsearch.dialect.model.impl.Elasticsearch814ModelDialect;
import org.hibernate.search.backend.elasticsearch.dialect.model.impl.Elasticsearch8ModelDialect;
import org.hibernate.search.backend.elasticsearch.dialect.model.impl.ElasticsearchModelDialect;
import org.hibernate.search.backend.elasticsearch.dialect.model.impl.OpenSearch1ModelDialect;
Expand Down Expand Up @@ -104,7 +105,11 @@ else if ( major == 7 ) {
if ( major == 8 && ( minorOptional.isEmpty() || minorOptional.getAsInt() < 12 ) ) {
return new Elasticsearch8ModelDialect();
}
return new Elasticsearch812ModelDialect();
if ( major == 8 && minorOptional.getAsInt() < 14 ) {
return new Elasticsearch812ModelDialect();
}

return new Elasticsearch814ModelDialect();
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/*
* Hibernate Search, full-text search for your domain model
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
package org.hibernate.search.backend.elasticsearch.dialect.model.impl;

import org.hibernate.search.backend.elasticsearch.types.dsl.provider.impl.Elasticsearch814IndexFieldTypeFactoryProvider;
import org.hibernate.search.backend.elasticsearch.types.dsl.provider.impl.ElasticsearchIndexFieldTypeFactoryProvider;
import org.hibernate.search.backend.elasticsearch.validation.impl.Elasticsearch814PropertyMappingValidatorProvider;
import org.hibernate.search.backend.elasticsearch.validation.impl.ElasticsearchPropertyMappingValidatorProvider;

import com.google.gson.Gson;

/**
* The model dialect for Elasticsearch 8.14+.
*/
public class Elasticsearch814ModelDialect implements ElasticsearchModelDialect {

@Override
public ElasticsearchIndexFieldTypeFactoryProvider createIndexTypeFieldFactoryProvider(Gson userFacingGson) {
return new Elasticsearch814IndexFieldTypeFactoryProvider( userFacingGson );
}

@Override
public ElasticsearchPropertyMappingValidatorProvider createElasticsearchPropertyMappingValidatorProvider() {
return new Elasticsearch814PropertyMappingValidatorProvider();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
import com.google.gson.Gson;

/**
* The index field type factory provider for ES8.12+.
* The index field type factory provider for ES8.12-8.13.
*/
public class Elasticsearch812IndexFieldTypeFactoryProvider extends AbstractIndexFieldTypeFactoryProvider {

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/*
* Hibernate Search, full-text search for your domain model
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
package org.hibernate.search.backend.elasticsearch.types.dsl.provider.impl;

import org.hibernate.search.backend.elasticsearch.types.mapping.impl.Elasticsearch814VectorFieldTypeMappingContributor;
import org.hibernate.search.backend.elasticsearch.types.mapping.impl.ElasticsearchVectorFieldTypeMappingContributor;

import com.google.gson.Gson;

/**
* The index field type factory provider for ES8.14+.
*/
public class Elasticsearch814IndexFieldTypeFactoryProvider extends AbstractIndexFieldTypeFactoryProvider {

private final Elasticsearch814VectorFieldTypeMappingContributor vectorFieldTypeMappingContributor =
new Elasticsearch814VectorFieldTypeMappingContributor();

public Elasticsearch814IndexFieldTypeFactoryProvider(Gson userFacingGson) {
super( userFacingGson );
}

@Override
protected ElasticsearchVectorFieldTypeMappingContributor vectorFieldTypeMappingContributor() {
return vectorFieldTypeMappingContributor;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ public void contribute(PropertyMapping mapping, Context context) {
if ( resolvedVectorSimilarity != null ) {
mapping.setSimilarity( resolvedVectorSimilarity );
}
if ( context.m() != null || context.efConstruction() != null ) {
if ( indexOptionAddCondition( context ) ) {
ElasticsearchDenseVectorIndexOptions indexOptions = new ElasticsearchDenseVectorIndexOptions();
indexOptions.setType( "hnsw" );
if ( context.m() != null ) {
Expand All @@ -39,6 +39,10 @@ public void contribute(PropertyMapping mapping, Context context) {
}
}

protected boolean indexOptionAddCondition(Context context) {
return context.m() != null || context.efConstruction() != null;
}

@Override
public <F> void contribute(ElasticsearchIndexValueFieldType.Builder<F> builder, Context context) {
builder.queryElementFactory( PredicateTypeKeys.KNN,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
/*
* Hibernate Search, full-text search for your domain model
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
package org.hibernate.search.backend.elasticsearch.types.mapping.impl;

public class Elasticsearch814VectorFieldTypeMappingContributor extends Elasticsearch812VectorFieldTypeMappingContributor {

@Override
protected boolean indexOptionAddCondition(Context context) {
// we want to always add index options and in particular include `hnsw` type.
return context.searchable();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
/*
* Hibernate Search, full-text search for your domain model
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
package org.hibernate.search.backend.elasticsearch.validation.impl;

import org.hibernate.search.backend.elasticsearch.lowlevel.index.mapping.impl.PropertyMapping;

public class Elasticsearch814PropertyMappingValidatorProvider implements ElasticsearchPropertyMappingValidatorProvider {
@Override
public Validator<PropertyMapping> create() {
return new PropertyMappingValidator.Elasticsearch814PropertyMappingValidator();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,24 @@ protected void validateVectorMapping(ValidationErrorCollector errorCollector, Pr
}
}

static class Elasticsearch812PropertyMappingValidator extends PropertyMappingValidator {
static class Elasticsearch812PropertyMappingValidator extends Elasticsearch8xPropertyMappingValidator {
}

static class Elasticsearch814PropertyMappingValidator extends Elasticsearch8xPropertyMappingValidator {
@Override
protected boolean indexOptionsRequireValidation(ElasticsearchDenseVectorIndexOptions expected,
ElasticsearchDenseVectorIndexOptions actual) {
if ( expected != null
&& actual == null
&& expected.getEfConstruction() == null && expected.getM() == null && expected.getType() != null ) {
// if we set type only then ES will not return the index option block ... so we skip
return false;
}
return super.indexOptionsRequireValidation( expected, actual );
}
}

static class Elasticsearch8xPropertyMappingValidator extends PropertyMappingValidator {

private final ElasticsearchDenseVectorIndexOptionsValidator indexOptionsValidator =
new ElasticsearchDenseVectorIndexOptionsValidator();
Expand All @@ -160,10 +177,16 @@ protected void validateVectorMapping(ValidationErrorCollector errorCollector, Pr
);

ElasticsearchDenseVectorIndexOptions indexOptions = expectedMapping.getIndexOptions();
if ( indexOptions != null ) {
indexOptionsValidator.validate( errorCollector, indexOptions, actualMapping.getIndexOptions() );
ElasticsearchDenseVectorIndexOptions actual = actualMapping.getIndexOptions();
if ( indexOptionsRequireValidation( indexOptions, actual ) ) {
indexOptionsValidator.validate( errorCollector, indexOptions, actual );
}
}

protected boolean indexOptionsRequireValidation(ElasticsearchDenseVectorIndexOptions expected,
ElasticsearchDenseVectorIndexOptions actual) {
return expected != null;
}
}

static class OpenSearch1PropertyMappingValidator extends PropertyMappingValidator {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
import org.hibernate.search.backend.elasticsearch.ElasticsearchVersion;
import org.hibernate.search.backend.elasticsearch.dialect.model.impl.Elasticsearch7ModelDialect;
import org.hibernate.search.backend.elasticsearch.dialect.model.impl.Elasticsearch812ModelDialect;
import org.hibernate.search.backend.elasticsearch.dialect.model.impl.Elasticsearch814ModelDialect;
import org.hibernate.search.backend.elasticsearch.dialect.model.impl.Elasticsearch8ModelDialect;
import org.hibernate.search.backend.elasticsearch.dialect.model.impl.ElasticsearchModelDialect;
import org.hibernate.search.backend.elasticsearch.dialect.model.impl.OpenSearch1ModelDialect;
Expand Down Expand Up @@ -259,23 +260,23 @@ public static List<? extends Arguments> params() {
),
success(
ElasticsearchDistributionName.ELASTIC, "8.14", "8.14.0",
Elasticsearch812ModelDialect.class, Elasticsearch81ProtocolDialect.class
Elasticsearch814ModelDialect.class, Elasticsearch81ProtocolDialect.class
),
success(
ElasticsearchDistributionName.ELASTIC, "8.14.0", "8.14.0",
Elasticsearch812ModelDialect.class, Elasticsearch81ProtocolDialect.class
Elasticsearch814ModelDialect.class, Elasticsearch81ProtocolDialect.class
),
successWithWarning(
ElasticsearchDistributionName.ELASTIC, "8.15", "8.15.0",
Elasticsearch812ModelDialect.class, Elasticsearch81ProtocolDialect.class
Elasticsearch814ModelDialect.class, Elasticsearch81ProtocolDialect.class
),
successWithWarning(
ElasticsearchDistributionName.ELASTIC, "8.15.0", "8.15.0",
Elasticsearch812ModelDialect.class, Elasticsearch81ProtocolDialect.class
Elasticsearch814ModelDialect.class, Elasticsearch81ProtocolDialect.class
),
successWithWarning(
ElasticsearchDistributionName.ELASTIC, "9.0.0", "9.0.0",
Elasticsearch812ModelDialect.class, Elasticsearch81ProtocolDialect.class
Elasticsearch814ModelDialect.class, Elasticsearch81ProtocolDialect.class
),
success(
ElasticsearchDistributionName.OPENSEARCH, "1", "1.3.1",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,15 +82,23 @@ public String vectorFieldMapping(int dim, Class<?> elementType, OptionalInt m, O
+ " 'element_type': '" + elementType.getName() + "',"
+ " 'dims': " + dim
+ similarity.map( s -> ", 'similarity': '" + s + "'" ).orElse( "" )
+ ( ( m.isPresent() || efConstruction.isPresent() )
? ( ", 'index_options': {"
+ ( m.isPresent() ? " 'm': " + m.getAsInt() + "," : "" )
+ ( efConstruction.isPresent()
? " 'ef_construction': " + efConstruction.getAsInt() + ","
: "" )
+ " 'type': 'hnsw'"
+ " }" )
: "" )
+ ( ( m.isPresent()
|| efConstruction.isPresent()
|| !isActualVersion(
esVersion -> esVersion.isLessThan( "8.14.0" ),
osVersion -> {
throw new AssertionFailure(
"OpenSearch cannot be called within this condition block" );
}
) )
? ( ", 'index_options': {"
+ ( m.isPresent() ? " 'm': " + m.getAsInt() + "," : "" )
+ ( efConstruction.isPresent()
? " 'ef_construction': " + efConstruction.getAsInt() + ","
: "" )
+ " 'type': 'hnsw'"
+ " }" )
: "" )
+ "}";
case OPENSEARCH:
case AMAZON_OPENSEARCH_SERVERLESS:
Expand Down

0 comments on commit 2e36d0e

Please sign in to comment.