美文网首页
Spring-data 整合 Elasticsearch

Spring-data 整合 Elasticsearch

作者: Crespo_Curry | 来源:发表于2020-09-29 07:45 被阅读0次

最近在项目使用了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));
  }

相关文章

网友评论

      本文标题:Spring-data 整合 Elasticsearch

      本文链接:https://www.haomeiwen.com/subject/fpusuktx.html