Допустим, у меня есть такое сопоставление, и я хочу выполнить поиск по полю «requestId.keyword», чтобы получить запросы на точное соответствие. Как я могу реализовать это с репозиторием Spring Data Elasticsearch без использования аннотации @Query?
"requestId": {
"type": "text",
"analyzer": "1_to_15_analyzer_without_space",
"search_analyzer": "all_symbols_and_fold_analyzer",
"fields": {
"keyword": {
"type": "keyword"
}
}
}
Это невозможно с механизмом построения запросов путем самоанализа имени метода. Первая идея состоит в том, чтобы иметь что-то вроде (здесь я использую сущность Foo
):
SearchHits<Foo> searchByRequestId_Keyword(String keyword);
Анализ имени метода выполняется в модуле spring-data-common, который использует только имена свойств Java-свойств объекта (могут быть вложенными). Но подполе ключевое слово существует только в Elasticsearch и — если не создано автоматически — в аннотации @MultiField
. Но код для анализа имени метода не использует информацию, специфичную для хранилища, поэтому такой подход не будет работать и завершится ошибкой, что keyword
не является свойством text
, что правильно для объекта Java.
Что вы можете сделать, так это сначала добавить пользовательский интерфейс фрагмента репозитория:
public interface FooKeywordRepository {
SearchHits<Foo> searchByRequestIdKeyword(String keyword);
}
и предоставьте реализацию, которая должна называться как интерфейс с суффиксом Внедрение:
import org.elasticsearch.index.query.QueryBuilders;
import org.springframework.data.elasticsearch.core.ElasticsearchOperations;
import org.springframework.data.elasticsearch.core.SearchHits;
import org.springframework.data.elasticsearch.core.query.Criteria;
import org.springframework.data.elasticsearch.core.query.CriteriaQuery;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.data.elasticsearch.core.query.Query;
public class FooKeywordRepositoryImpl implements FooKeywordRepository {
private final ElasticsearchOperations operations;
public FooKeywordRepositoryImpl(ElasticsearchOperations operations) {
this.operations = operations;
}
@Override
public SearchHits<Foo> searchByRequestIdKeyword(String keyword) {
Query query1 = new NativeSearchQueryBuilder()
.withQuery(QueryBuilders.termQuery("requestId.keyword", keyword))
.build();
Query query2 = new CriteriaQuery(Criteria.where("requestId.keyword").is(keyword));
return operations.search(query1, Foo.class); // could be query2 as well
}
}
У вас есть инъекция ElasticsearchOperations
, и вы используете ее для выполнения запроса, который вы создаете. Я указал два способа построения запроса, оба работают.
Ваше определение репозитория для использования будет таким:
public interface FooRepository extends ElasticsearchRepository<Foo, String>, FooKeywordRepository {
// other custom methods if needed
}