1、ElasticsearchClient客户端依赖

使用spring-boot-2.6.4的版本演示客户端,加入以下依赖

<dependency>
    <groupId>co.elastic.clients</groupId>
    <artifactId>elasticsearch-java</artifactId>
    <version>8.1.0</version>
</dependency>
<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.12.3</version>
</dependency>
2、java客户端操作案例
  • 初始化client
public void init() {
    String auth = Base64Utils.encodeToString("elastic:elastic8888".getBytes());
    Header authHeader = new BasicHeader("Authorization", String.format("Basic %s", auth));
    Header[] header = {authHeader};
    RestClient restClient = RestClient.builder(new HttpHost("192.168.91.138", 9200), new HttpHost("192.168.91.136", 9200)).setDefaultHeaders(header).build();
    ElasticsearchTransport transport = new RestClientTransport(restClient, new JacksonJsonpMapper());
    ElasticsearchClient client = new ElasticsearchClient(transport);
}
  • 2.1 创建索引

可以根据一个实体的字段完成默认索引的创建和mapping的生成,其中字符串字段默认为text,若需要使用关键字,如姓名查询,需要重新生成mapping

创建一个Article文章类

public class Article {

    private String id;

    private String author;

    private String title;

    private String content;

    private int star;

    private int type;

    private Date createDate;

}

字段都已经赋了默认值,所以创建索引以及生成默认的mapping可以按以下create方法

Article a = Article.builder().id("").author("").title("").content("").star(0).type(0).createDate(new Date()).build();
CreateResponse response = client.create(e -> e.index("index-article-master").document(a).id("1"));
log.info("{}", response.result().name());

这段代码做了几件事情,创建了索引index-article-master以及对应的mapping,并且插入了一条id为1的数据;

  • 2.2、索引数据

初始化两条测试数据

Article article = Article.builder().id("3").author("迷你茶").star(3).title("3c类产品").content("电脑、手机、电视").type(1).createDate(new Date()).build();
IndexRequest<Article> ir = new IndexRequest.Builder().index("index-article-master").id(article.getId()).document(article).build();
client.index(ir);

article = Article.builder().id("4").author("迷你茶").star(5).title("手机销量").content("华为、小米、苹果").type(2).createDate(new Date()).build();
ir = new IndexRequest.Builder().index("index-article-master").id(article.getId()).document(article).build();
client.index(ir);

按默认创建的mappingauthor的类型是text,是会被分词检索的,但现实中姓名分词没有意义是不需要分词的,所以需要修改其类型为keywordGET http://192.168.91.138:9200/index-article-master/_search?q=迷你

  • 2.3、变更mapping

由于es是不支持直接修改文档的mapping的,可以允许新增mapping字段,所以变更一个已经存在的字段类型需要借助一个新的index来解决;

首先是需要获取已存在的mapping

GET http://192.168.91.138:9200/index-article-master/_mapping

获取到mapping后将字段author改为keyword重新创建一个索引index-article-backup

PUT http://192.168.91.138:9200/index-article-backup
{
    "mappings": {
        "properties": {
            "author": {
                "type": "keyword"
            },
            ...... 其余省略
        }
    }
}

再将索引index-article-master的数据同步到index-article-backup中,使用的是_reindex

POST http://192.168.91.138:9200/_reindex
{
    "source": {
        "index": "index-article-master"
    },
    "dest": {
        "index": "index-article-backup"
    }
}

数据同步完成后,可删除索引index-article-master,再使用名称的一部分迷你作为查询条件就查不出了GET http://192.168.91.138:9200/index-article-backup/_search?q=迷你,需要使用完整的关键字迷你茶才可查询

通常情况下,我们在应用中使用别名index-article来操作,涉及到结构的变化时只需要将别名来回在masterbackup中切换即可

  • 2.4 索引别名

创建索引别名

PutAliasRequest request = new PutAliasRequest.Builder().index("index-article-backup").name("index-article").build();
PutAliasResponse response = client.indices().putAlias(request);
log.info("acknowledged {}", response.acknowledged());

删除索引别名

DeleteAliasResponse response = client.indices().deleteAlias(e -> e.index("test-create-2").name("test-create-2-backup"));
log.info("acknowledged {}", response.acknowledged());

查询所有索引别名

GetAliasResponse alias = client.indices().getAlias();
for (Map.Entry<String, IndexAliases> entry : alias.result().entrySet()) {
    for (Map.Entry<String, AliasDefinition> e : entry.getValue().aliases().entrySet()) {
        log.info("索引: {} 别名: {}", entry.getKey(), e.getKey());
    }
}
  • 2.5、删除索引数据
DeleteResponse response = client.delete(e -> e.index("index-article").id("1"));
log.info("{} {}", this.toString(), response.result().name());
  • 2.6、搜索数据/权重搜索

简单全文检索含手机关键字的文章,代码如下

SearchResponse<Article> result = client.search(e -> e.index("index-article").q("手机"), Article.class);
for (Hit<Article> hit : result.hits().hits()) {
    log.info("{}", JSON.toJSONString(hit.source()));
}

通常情况下,搜索关键字手机时,在文章的标题中包含手机的权重要比在内容中包含手机的权重要高,所以我们可以通过boost提升标题的权重从而影响打分实现排序

SearchResponse<Article> result = client.search(e->e.index("index-article").query(q->q.boosting(b->b.negativeBoost(0.5f)
        .negative(ne->ne.queryString(qs->qs.fields("content").query("手机")))
        .positive(po->po.queryString(qs->qs.query("手机"))))),Article.class);
for (Hit<Article> hit : result.hits().hits()) {
    log.info("{} - {}", hit.score(), JSON.toJSONString(hit.source()));
}

positive 表示查询条件,只有匹配的内容,才能被搜索出来 negative 在根据positive的查询条件查出来的结果集中,如果又符合negative,就会按参数negative_boost系数降低文档的分数,这个系数必须小于1.0,比如10分的话,这个系数为0.5就是5分


赞赏(Donation)
微信(Wechat Pay)

donation-wechatpay