如何使用 Spring 数据从 elasticsearch 中读取文档?
How to read documents from elasticsearch using Spring Data?
我创建了一个类型为 "apartments" 的索引(房子),其中包含 20 个文档。我使用邮递员将 Json 作为二进制文件上传到 elasticsearch 中。我有一个 Spring 引导项目,它具有以下内容 类:
EsConfig.java - 我已经配置了 clustername,它是 application.properties 文件中的默认名称。
@Configuration
@EnableElasticsearchRepositories(basePackages = "com.search.repository")
public class EsConfig {
@Value("${elasticsearch.clustername}")
private String EsClusterName;
@Bean
public Client esClient() throws UnknownHostException {
Settings esSettings = Settings.builder()
.put("cluster.name", EsClusterName)
.put("client.transport.sniff", true)
.put("client.transport.ignore_cluster_name", false)
.build();
TransportClient client = new PreBuiltTransportClient(esSettings)
.addTransportAddress(new InetSocketTransportAddress(InetAddress.getByName("localhost"), 9300));
return client;
}
@Bean
public ElasticsearchOperations elasticsearchTemplate() throws Exception{
return new ElasticsearchTemplate(esClient());
}
}
Apartments.java - 这是我的数据模型。这些文件在 elasticsearch 中有以下字段。
@Document(indexName = "house", type = "apartments")
@JsonIgnoreProperties(ignoreUnknown=true)
public class Apartments {
@Id
private String id;
@JsonProperty("Apartment_Name")
private String apartmentName;
@JsonProperty("Apartment_ID")
private String apartmentId;
@JsonProperty("Area_Name")
private String areaName;
//constructors along with getters and setters
}
ApartmentSearchRepository.java - 这是一个扩展 ElasticsearchRepository 接口以执行 crud 操作的接口。
public interface ApartmentSearchRepository extends ElasticsearchRepository<Apartments, String> {
List<Apartments> findByApartmentName(String apartmentName);
}
EsApartmentService.java -
@Service
public class EsApartmentService {
@Autowired
ApartmentSearchRepository apartmentSearchRepository;
public List<Apartments> getApartmentByName(String apartmentName) {
return apartmentSearchRepository.findByApartmentName(apartmentName);
}
}
ApartmentController.java - 我创建了一个端点,它应该从 elasticsearch 返回这 20 个文档。 (此外,Apartment 在我的项目中是一个 POJO,Apartments 是数据模型。)
@Autowired
EsApartmentService esApartmentService;
@GetMapping(path = "/search",produces = "application/json")
public Set<Apartment> searchApartmentByName(
@RequestParam(value = "apartmentName", defaultValue = "") String apartmentName) throws IOException {
List<Apartment> apartments= new ArrayList<>();
esApartmentService.getApartmentByName(apartmentName).forEach(apartment-> {
apartments.add(new Apartment(apartment.getApartmentName(), apartment.getApartmentId(), apartment.getAreaName()));
});
return apartments.stream()
.collect(Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(Apartment::getApartmentId))));
}
此代码返回状态 200,但响应为空。我试过调试,但似乎无法从 elasticsearch 中读取这些文档。我经历了几个解决方案,但大多数解决方案都是从代码本身设置文档数据。
我无法通过点击我在控制器中指定的端点来检索这些文档。有人可以让我知道我可能会错过什么吗?谢谢! :)
编辑: 下面的屏幕截图显示了 Postman 中的查询和响应。
据我所知,您可以使用@JsonProperty 将 POJO 映射到查询响应,但您将失去使用 spring 的动态查找器方法 (findBy*) 的能力数据。 spring 数据的动态查找器生成依赖于反射,因此 POJO 中的字段名称变得很重要。
您是否介意更改您的 POJO 或文档中的字段名称以验证这一点?或者只是定义一个自定义查询?还有一个强大的 java api ,您可以在其中定义更复杂的查询:https://docs.spring.io/spring-data/elasticsearch/docs/current/reference/html/#elasticsearch.misc.filter
正如@ibexit 上面提到的,我删除了@JsonProperty 并在我的服务中使用了本机搜索查询生成器。此外,它没有使用 Apartment_Name,当我提供 apartment_Name 时它起作用了。 (好像 Elasticsearch 有大小写问题,所以我用 Camel Case 给了它。)
我的改动:
Apartments.java - 删除了@JsonProperty
@Document(indexName = "house", type = "apartments")
//@JsonIgnoreProperties(ignoreUnknown=true)
public class Apartments {
@Id
private String id;
//@JsonProperty("apartment_ID")
private String apartment_ID;
//@JsonProperty("Area_Name")
private String area_Name;
//@JsonProperty("Apartment_Name")
private String apartment_Name;
}
EsApartmentService.java -
@Service
public class EsApartmentService {
@Autowired
private ElasticsearchTemplate elasticsearchTemplate;
public List<Apartments> getApartmentByName(String apartmentName) {
SearchQuery searchQuery = new NativeSearchQueryBuilder()
.withQuery(org.elasticsearch.index.query.QueryBuilders
.matchQuery("apartment_Name", apartmentName)).build();
Page<Apartments> sampleEntities =
elasticsearchTemplate.queryForPage(searchQuery,Apartments.class);
return sampleEntities.getContent();
}
}
- 已删除 ApartmentSearchRepository.java 文件。
这些更改给了我所需的响应! :)
我创建了一个类型为 "apartments" 的索引(房子),其中包含 20 个文档。我使用邮递员将 Json 作为二进制文件上传到 elasticsearch 中。我有一个 Spring 引导项目,它具有以下内容 类:
EsConfig.java - 我已经配置了 clustername,它是 application.properties 文件中的默认名称。
@Configuration @EnableElasticsearchRepositories(basePackages = "com.search.repository") public class EsConfig { @Value("${elasticsearch.clustername}") private String EsClusterName; @Bean public Client esClient() throws UnknownHostException { Settings esSettings = Settings.builder() .put("cluster.name", EsClusterName) .put("client.transport.sniff", true) .put("client.transport.ignore_cluster_name", false) .build(); TransportClient client = new PreBuiltTransportClient(esSettings) .addTransportAddress(new InetSocketTransportAddress(InetAddress.getByName("localhost"), 9300)); return client; } @Bean public ElasticsearchOperations elasticsearchTemplate() throws Exception{ return new ElasticsearchTemplate(esClient()); } }
Apartments.java - 这是我的数据模型。这些文件在 elasticsearch 中有以下字段。
@Document(indexName = "house", type = "apartments") @JsonIgnoreProperties(ignoreUnknown=true) public class Apartments { @Id private String id; @JsonProperty("Apartment_Name") private String apartmentName; @JsonProperty("Apartment_ID") private String apartmentId; @JsonProperty("Area_Name") private String areaName; //constructors along with getters and setters }
ApartmentSearchRepository.java - 这是一个扩展 ElasticsearchRepository 接口以执行 crud 操作的接口。
public interface ApartmentSearchRepository extends ElasticsearchRepository<Apartments, String> { List<Apartments> findByApartmentName(String apartmentName); }
EsApartmentService.java -
@Service public class EsApartmentService { @Autowired ApartmentSearchRepository apartmentSearchRepository; public List<Apartments> getApartmentByName(String apartmentName) { return apartmentSearchRepository.findByApartmentName(apartmentName); } }
ApartmentController.java - 我创建了一个端点,它应该从 elasticsearch 返回这 20 个文档。 (此外,Apartment 在我的项目中是一个 POJO,Apartments 是数据模型。)
@Autowired EsApartmentService esApartmentService; @GetMapping(path = "/search",produces = "application/json") public Set<Apartment> searchApartmentByName( @RequestParam(value = "apartmentName", defaultValue = "") String apartmentName) throws IOException { List<Apartment> apartments= new ArrayList<>(); esApartmentService.getApartmentByName(apartmentName).forEach(apartment-> { apartments.add(new Apartment(apartment.getApartmentName(), apartment.getApartmentId(), apartment.getAreaName())); }); return apartments.stream() .collect(Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(Apartment::getApartmentId)))); }
此代码返回状态 200,但响应为空。我试过调试,但似乎无法从 elasticsearch 中读取这些文档。我经历了几个解决方案,但大多数解决方案都是从代码本身设置文档数据。
我无法通过点击我在控制器中指定的端点来检索这些文档。有人可以让我知道我可能会错过什么吗?谢谢! :)
编辑: 下面的屏幕截图显示了 Postman 中的查询和响应。
据我所知,您可以使用@JsonProperty 将 POJO 映射到查询响应,但您将失去使用 spring 的动态查找器方法 (findBy*) 的能力数据。 spring 数据的动态查找器生成依赖于反射,因此 POJO 中的字段名称变得很重要。
您是否介意更改您的 POJO 或文档中的字段名称以验证这一点?或者只是定义一个自定义查询?还有一个强大的 java api ,您可以在其中定义更复杂的查询:https://docs.spring.io/spring-data/elasticsearch/docs/current/reference/html/#elasticsearch.misc.filter
正如@ibexit 上面提到的,我删除了@JsonProperty 并在我的服务中使用了本机搜索查询生成器。此外,它没有使用 Apartment_Name,当我提供 apartment_Name 时它起作用了。 (好像 Elasticsearch 有大小写问题,所以我用 Camel Case 给了它。)
我的改动:
Apartments.java - 删除了@JsonProperty
@Document(indexName = "house", type = "apartments") //@JsonIgnoreProperties(ignoreUnknown=true) public class Apartments { @Id private String id; //@JsonProperty("apartment_ID") private String apartment_ID; //@JsonProperty("Area_Name") private String area_Name; //@JsonProperty("Apartment_Name") private String apartment_Name; }
EsApartmentService.java -
@Service public class EsApartmentService { @Autowired private ElasticsearchTemplate elasticsearchTemplate; public List<Apartments> getApartmentByName(String apartmentName) { SearchQuery searchQuery = new NativeSearchQueryBuilder() .withQuery(org.elasticsearch.index.query.QueryBuilders .matchQuery("apartment_Name", apartmentName)).build(); Page<Apartments> sampleEntities = elasticsearchTemplate.queryForPage(searchQuery,Apartments.class); return sampleEntities.getContent(); } }
- 已删除 ApartmentSearchRepository.java 文件。
这些更改给了我所需的响应! :)