最近在项目使用了Elasticsearch,整理如下的整合流程。
一. 版本的匹配
我们这里用Spring Boot 2.2.0根据自己项目要求的版本进行匹配
二. 导入引用的Spring-data-elasticsearch
<!-- https://docs.spring.io/spring-data/elasticsearch/docs/3.2.x/reference/html -->
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-elasticsearch</artifactId>
<version>3.2.0.RELEASE</version>
</dependency>
三. Elasticsearch Config
@Configuration
@ConfigurationProperties(prefix = "elastic-search")
@EnableElasticsearchRepositories(
basePackages = "com.XX.repository")
public class ElasticsearchConfig extends AbstractElasticsearchConfiguration {
private String host;
private int port;
private String userName;
private String password;
private String certificateBase64;
private static final String HTTPS = "https";
@Autowired
private LogService logService;
@Bean
@Override
public RestHighLevelClient elasticsearchClient() {
if (StringUtils.isEmpty(certificateBase64)) {
logService.info(getClass(), "Run the mode of JRE installation certificate.");
final CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
credentialsProvider.setCredentials(AuthScope.ANY,
new UsernamePasswordCredentials(userName, password));
RestClientBuilder builder = RestClient.builder(new HttpHost(host, port, HTTPS))
.setHttpClientConfigCallback(httpClientBuilder -> httpClientBuilder
.setDefaultCredentialsProvider(credentialsProvider));
return new RestHighLevelClient(builder);
} else {
ClientConfiguration clientConfiguration = ClientConfiguration.builder()
.connectedTo(host + ":" + port).usingSsl(this.getSSLContext(certificateBase64))
.withBasicAuth(userName, password).build();
return RestClients.create(clientConfiguration).rest();
}
}
@Bean
@Override
public EntityMapper entityMapper() {
ElasticsearchEntityMapper entityMapper = new ElasticsearchEntityMapper(
elasticsearchMappingContext(), new DefaultConversionService());
entityMapper.setConversions(elasticsearchCustomConversions());
return entityMapper;
}
private SSLContext getSSLContext(String base64Cert) {
SSLContext sslContext = null;
try {
sslContext = SSLContext.getInstance("TLSv1.2");
InputStream is = new ByteArrayInputStream(Base64.getDecoder().decode(base64Cert));
CertificateFactory cf = CertificateFactory.getInstance("X.509");
X509Certificate caCert = (X509Certificate) cf.generateCertificate(is);
TrustManagerFactory tmf =
TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
ks.load(null);
ks.setCertificateEntry("caCert", caCert);
tmf.init(ks);
sslContext.init(null, tmf.getTrustManagers(), null);
} catch (Exception e) {
logService.error(getClass(), "load ssl error." + e.getMessage());
}
return sslContext;
}
四. 写实体类和Repository
- Entity
@Document(indexName = "es_knowledge", type = "knowledge")
public class KnowledgeEs {
@Id
private String id;
private String updatedBy;
private Date updatedOn;
private Map<String, Integer> ratings = new HashMap<>();
- CrudRepository
public interface KnowledgeEsRepository extends ElasticsearchRepository<KnowledgeEs, String> {
@Query("{\"bool\" : {\"must\" : {\"field\" : {\"subject.keyword\" : \"?\"}}}}")
Page<KnowledgeEs> findBySubject(String subject, Pageable pageable);
@Query("{\"bool\" : {\"must\" : {\"field\" : {\"content.keyword\" : \"?\"}}}}")
Page<KnowledgeEs> findByContent(String content, Pageable pageable);
}
-
CustomRepository 利用了RestHighLevelClient的rest client
里面包含(权重,高亮)的查询
@Repository
public class KnowledgeCustomEsRepositoryImpl implements KnowledgeCustomEsRepository {
@Autowired
RestHighLevelClient highLevelClient;
@Override
public List<Knowledge> getKnowledgesVisible(String enterpriseId, String teamId, String channelId,
String keyword) {
SearchRequest searchRequest = new SearchRequest(INDEX);
SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
// search by keyword
this.enrichKeywordQuery(keyword, boolQueryBuilder);
// Boost
this.enrichShouldBoostQuery(boolQueryBuilder, enterpriseId, teamId, channelId);
sourceBuilder.query(boolQueryBuilder);
// Highlight
this.enrichHighlightBuilder(sourceBuilder);
searchRequest.source(sourceBuilder);
SearchResponse response;
try {
response = highLevelClient.search(searchRequest, RequestOptions.DEFAULT);
} catch (IOException e) {
logService.error(getClass(), "es query fail." + e.getMessage());
return new ArrayList<>();
}
// deal result
List<Knowledge> knowledges = new ArrayList<>();
for (SearchHit hit : response.getHits()) {
try {
Knowledge knowledge =
new ObjectMapper().readValue(hit.getSourceAsString(), Knowledge.class);
Map<String, HighlightField> highlightMap = hit.getHighlightFields();
if (!highlightMap.isEmpty()) {
if (highlightMap.get(CONTENT) != null
&& !ArrayUtils.isEmpty(highlightMap.get(CONTENT).getFragments())) {
knowledge.setContent(highlightMap.get(CONTENT).getFragments()[0].toString());
}
if (highlightMap.get(SUBJECT) != null
&& !ArrayUtils.isEmpty(highlightMap.get(SUBJECT).getFragments())) {
knowledge.setSubject(highlightMap.get(SUBJECT).getFragments()[0].toString());
}
}
knowledge.setId(hit.getId());
knowledges.add(knowledge);
} catch (JsonProcessingException e) {
logService.error(getClass(), "SearchHit to enity excption." + e.getMessage());
}
}
return knowledges;
}
/**
* search by keyword
*
* @param filters
* @param queryBuilder
*/
private void enrichKeywordQuery(String keyword, BoolQueryBuilder queryBuilder) {
if (!StringUtils.isEmpty(keyword)) {
String queryString = keyword.trim();
if (queryString.contains(",")) {
String[] queryArray = queryString.split(",");
for (String value : queryArray) {
// if query value is a comma separated values, then use AND operator between values
if (!value.isEmpty()) {
queryBuilder.must(QueryBuilders.queryStringQuery(value).analyzer(STOP_ANALYZER));
}
}
} else if (queryString.startsWith("\"") && queryString.endsWith("\"")) {
// exact match
queryBuilder.must(QueryBuilders.queryStringQuery(queryString));
} else if (!queryString.contains(" ")) {
// to prevent elasticsearch from parsing email
StringBuilder queryValue = new StringBuilder();
queryValue.append("\"" + queryString + "\"");
queryBuilder.must(QueryBuilders.queryStringQuery(queryValue.toString()));
} else {
queryBuilder.must(QueryBuilders.queryStringQuery(queryString).analyzer(STOP_ANALYZER));
}
}
}
/**
* HighlightBuilder
*
* @param sourceBuilder
*/
private void enrichHighlightBuilder(SearchSourceBuilder sourceBuilder) {
// highlight
HighlightBuilder highlightBuilder = new HighlightBuilder();
highlightBuilder.preTags("*");
highlightBuilder.postTags("*");
highlightBuilder.fields().addAll(
Arrays.asList(new HighlightBuilder.Field(SUBJECT), new HighlightBuilder.Field(CONTENT)));
sourceBuilder.highlighter(highlightBuilder);
}
/**
* Boost
*
* @param boolQueryBuilder
* @param enterpriseId
* @param teamId
* @param channelId
*/
private void enrichShouldBoostQuery(BoolQueryBuilder boolQueryBuilder, String enterpriseId,
String teamId, String channelId) {
BoolQueryBuilder shouldBoolQueryBuilder = QueryBuilders.boolQuery();
// Query according to enterpriseId, teamId, channelId, with the highest weight
BoolQueryBuilder queryEnterpriseTeamChannel = QueryBuilders.boolQuery();
queryEnterpriseTeamChannel
.must(QueryBuilders.termQuery(FieldNames.CHANNEL_ID + KEYWORD, channelId).boost(2.0f))
.must(QueryBuilders.termQuery(FieldNames.TEAM_ID + KEYWORD, teamId).boost(2.0f))
.must(StringUtils.isEmpty(enterpriseId)
? QueryBuilders.termsQuery(FieldNames.ENTERPRISE_ID + KEYWORD, Arrays.asList("", null))
: QueryBuilders.termQuery(FieldNames.ENTERPRISE_ID + KEYWORD, enterpriseId)
.boost(2.0f));
shouldBoolQueryBuilder.should(queryEnterpriseTeamChannel.boost(2.0f));
// Query according to enterpriseId, teamId , level is ENTERPRISE ,WORKSPACE
BoolQueryBuilder queryEnterpriseTeam = QueryBuilders.boolQuery();
queryEnterpriseTeam.must(QueryBuilders.termQuery(FieldNames.TEAM_ID + KEYWORD, teamId))
.must(StringUtils.isEmpty(enterpriseId)
? QueryBuilders.termsQuery(FieldNames.ENTERPRISE_ID + KEYWORD, Arrays.asList("", null))
: QueryBuilders.termQuery(FieldNames.ENTERPRISE_ID + KEYWORD, enterpriseId))
.mustNot(QueryBuilders.termQuery(FieldNames.CHANNEL_ID + KEYWORD, channelId))
.must(QueryBuilders.termsQuery(FIELD_LEVEL + KEYWORD, Arrays
.asList(KnowledgeLevel.ENTERPRISE.getName(), KnowledgeLevel.WORKSPACE.getName())));
shouldBoolQueryBuilder.should(queryEnterpriseTeam);
// Query according to enterpriseId ,level is ENTERPRISE
BoolQueryBuilder queryEnterprise = QueryBuilders.boolQuery();
queryEnterprise
.must(StringUtils.isEmpty(enterpriseId)
? QueryBuilders.termsQuery(FieldNames.ENTERPRISE_ID + KEYWORD, Arrays.asList("", null))
: QueryBuilders.termQuery(FieldNames.ENTERPRISE_ID + KEYWORD, enterpriseId))
.mustNot(QueryBuilders.termQuery(FieldNames.TEAM_ID + KEYWORD, teamId))
.mustNot(QueryBuilders.termQuery(FieldNames.CHANNEL_ID + KEYWORD, channelId))
.must(QueryBuilders.termQuery(FIELD_LEVEL + KEYWORD, KnowledgeLevel.ENTERPRISE.getName())
.boost(1.7f));
shouldBoolQueryBuilder.should(queryEnterprise);
boolQueryBuilder.must(shouldBoolQueryBuilder.minimumShouldMatch(1));
}
网友评论