elasticsearch入门到放弃之springboot elasticsearch x-pack

代码地址:https://github.com/zhaoyunxing92/spring-boot-learn-box/tree/master/spring-boot-elasticsearch/spring-boot-data-elasticsearch

这个就跟我在以前写的【springboot mongodb配置解析】一样效果,单纯的以为设置好正好密码就可以很嗨皮的使用mongodb了,elasticsearch同样也遇到了该问题。期间的过程我不想多说了,直接往下看吧.(下面主要在x-pack开启模式下使用,正常模式下很简单不写了)

系列文章

参考文档

环境信息

环境信息很重要,不然很难成功

  • jdk 1.8
  • elasticsearch 6.4.0
  • x-pack 6.4.0
  • spring-boot-starter-data-elasticsearch 6.4.0
  • spring-boot 2.1.0 (它默认带的elasticsearch是6.2.2的)

pom.xml文件

 <!--修改es版本这样设置最简单-->
<properties>
    <elasticsearch.version>6.4.0</elasticsearch.version>
</properties>

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-elasticsearch</artifactId>
    <exclusions>
        <exclusion>
            <groupId>org.elasticsearch.client</groupId>
            <artifactId>transport</artifactId>
        </exclusion>
    </exclusions>
</dependency>
<dependency>
    <groupId>org.elasticsearch.client</groupId>
    <artifactId>x-pack-transport</artifactId>
    <version>${elasticsearch.version}</version>
</dependency>

<!--这个好像要添加不然下载不到 spring-boot-starter-data-elasticsearch:6.4.0 -->
<repository>
    <id>spring-libs-snapshot</id>
    <name>Spring Snapshot Repository</name>
    <url>https://repo.spring.io/libs-snapshot</url>
</repository>

application.yml配置

spring:
  data:
    elasticsearch:
      repositories:
        enabled: true
      cluster-nodes: 172.26.104.209:9300 # 集群模式下用逗号分开
      cluster-name: elasticsearch
      properties:
        xpack.security.user: elastic:123456

spring-data-elasticsearch 主键解释

@Document

这个主键对应的ElasticsearchCase#createIndex()方法

  • indexName 索引名称
  • type 类型
  • useServerConfiguration 是否使用系统配置
  • shards 集群模式下分片存储,默认分5片
  • replicas 数据复制几份,默认一份
  • refreshInterval 多久刷新数据 默认:1s
  • indexStoreType 索引存储模式 默认:fs,为深入研究
  • createIndex 是否创建索引,默认:true

@Id

看名字就知道了,不解释了

@Field

这个主键对应的ElasticsearchCase#setMappings()方法

  • type 字段类型 默认根据java类型推断,可选类型:Text,Integer,Long,Date,Float,Double,Boolean,Object,Auto,Nested,Ip,Attachment,Keyword,新的数据类型请参考官网
  • index 应该是建索引没有研究过
  • format 数据格式,可以理解为一个正则拦截可存储的数据格式
  • pattern 使用场景:format = DateFormat.custom, pattern = "yyyy-MM-dd HH:mm:ss:SSS"
  • searchAnalyzer 搜索的分词,新的ik分词只有ik_smartik_max_word两个模式
  • store 是否单独存储,应该是存储在_source
  • analyzer 分词模式
  • ignoreFields 没有研究过
  • includeInParent 没有研究过
  • fielddata 没有研究过

spring-data-elasticsearch 正式编码

我这里是重写了TransportClient类,不过很抱歉elasticsearch的开发者说到8.0就换一种方式了。issues#188983

ElasticsearchConfig.java

主要是替换TransportClientFactoryBeanPreBuiltXPackTransportClient,支持x-pack

/**
 * @author zhaoyunxing
 * @date: 2019-07-07 09:47
 * @des: es 配置类
 * @see org.springframework.data.elasticsearch.client.TransportClientFactoryBean
 * @see org.springframework.data.elasticsearch.client.ClusterNodes
 */
@Configuration
@EnableConfigurationProperties(ElasticsearchProperties.class)
public class ElasticsearchConfig {

    private final ElasticsearchProperties properties;

    public ElasticsearchConfig(ElasticsearchProperties properties) {
        this.properties = properties;
    }

    @Bean
    public TransportClient transportClient(){
        return new PreBuiltXPackTransportClient(settings())
                .addTransportAddresses(addresses());
    }

    /**
     * .put("client.transport.sniff", true)
     * .put("client.transport.ignore_cluster_name", false)
     * .put("client.transport.ping_timeout", clientPingTimeout)
     * .put("client.transport.nodes_sampler_interval", clientNodesSamplerInterval)
     *
     * @return Settings
     */
    private Settings settings() {
        Settings.Builder builder = Settings.builder();
        builder.put("cluster.name", properties.getClusterName());
        properties.getProperties().forEach(builder::put);
        return builder.build();
    }

    private TransportAddress[] addresses() {
        String clusterNodesStr = properties.getClusterNodes();
        Assert.hasText(clusterNodesStr, "Cluster nodes source must not be null or empty!");
        String[] nodes = StringUtils.delimitedListToStringArray(clusterNodesStr, ",");

        return Arrays.stream(nodes).map(node -> {
            String[] segments = StringUtils.delimitedListToStringArray(node, ":");
            Assert.isTrue(segments.length == 2,
                    () -> String.format("Invalid cluster node %s in %s! Must be in the format host:port!", node, clusterNodesStr));
            String host = segments[0].trim();
            String port = segments[1].trim();
            Assert.hasText(host, () -> String.format("No host name given cluster node %s!", node));
            Assert.hasText(port, () -> String.format("No port given in cluster node %s!", node));
            return new TransportAddress(toInetAddress(host), Integer.valueOf(port));
        }).toArray(TransportAddress[]::new);
    }

    private static InetAddress toInetAddress(String host) {
        try {
            return InetAddress.getByName(host);
        } catch (UnknownHostException ex) {
            throw new IllegalArgumentException(ex);
        }
    }
}

Article.java

主要看点是我时间格式的处理解决上篇【elasticsearch入门到放弃之elasticsearch-in-java】遗留的问题

/**
 * @author zhaoyunxing
 * @date: 2019-06-28 14:38
 * @des:
 */
@Data
@ToString
@AllArgsConstructor
@NoArgsConstructor
@Document(indexName = "blog", type = "article")
public class Article {
    @Id
    @Field(type = FieldType.Text, store = false)
    private String id;
    /**
     * 文章名称
     */
    @Field(type = FieldType.Text, store = true, analyzer = "ik_smart", searchAnalyzer = "ik_max_word")
    private String name;
    /**
     * 内容
     */
    @Field(type = FieldType.Text, store = true, analyzer = "ik_smart", searchAnalyzer = "ik_max_word")
    private String content;
    /**
     * 创建时间 采用自定义的时间格式
     */
    @Field(type = FieldType.Date, store = true, format = DateFormat.custom, pattern = "yyyy-MM-dd HH:mm:ss:SSS||yyyy-MM-dd||epoch_millis||date_optional_time")
    @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss:SSS", timezone = "GMT+8")
    private Date createTime;
}

CURD操作

这里你只要熟悉spring-data-elasticsearch的命名规则就很嗨皮的编写代码的,不了解就去翻文档吧,IDAE编辑器也会提示你怎么写。我就直接贴代码了

@RunWith(SpringRunner.class)
@SpringBootTest
public class ElasticsearchCase {

    @Autowired
    private ArticleService articleService;
    @Autowired
    private ElasticsearchTemplate elasticsearchTemplate;

    /**
     * 创建文章,更新文档只有保证id一直就可以了
     */
    @Test
    public void addDocument() {
        System.out.println("***********************一次性插入30条数据***********************");
        List<Article> articles = new ArrayList<>(30);
        for (int i = 1; i <= 30; i++) {
            Article article = new Article();
            article.setName("elasticsearch入门到放弃之docker搭建" + i);
            article.setContent("在我的观念里elasticsearch是" + i + "大数据的产物");
            article.setCreateTime(new Date());
            article.setId(String.valueOf(i));
            articles.add(article);
        }
        articleService.saveAll(articles);
    }

    /**
     * 查询全部 默认是查询10条数据的,但是findAll()查询的是全部数据,说明它真的是findAll()
     */
    @Test
    public void findAll() {
        System.out.println("***********************获取全部数据***********************");
        articleService.findAll().forEach(System.out::println);
    }

    /**
     * 根据id查询
     */
    @Test
    public void findById() {
        System.out.println("***********************根据id查询***********************");
        Article article = articleService.findById(String.valueOf(27)).orElseGet(Article::new);
        System.out.println(article);
    }

    /**
     * 根据名称查询 默认值返回10条数据
     */
    @Test
    public void findByName() {
        System.out.println("***********************根据名称查询***********************");
        articleService.findArticleByName("docker搭建").forEach(System.out::println);
    }

    /**
     * 标题中包含或者内容中包含,设置分页 三条数据分页
     */
    @Test
    public void findArticleByNameOrContent() {
        System.out.println("***********************根据名称和内容查询***********************");
        articleService.findArticleByNameOrContent("docker搭建", "30", PageRequest.of(0, 3)).forEach(System.out::println);
    }

    /**
     * 指定时间域名并且根据id进行deac排序(aec)类似不写了
     */
    @Test
    public void findArticlesByCreateTimeBetweenAndOrderByCreateTimeDesc() {
        System.out.println("***********************指定时间域名并且根据id进行deac排序***********************");

        articleService.findArticlesByCreateTimeBetweenOrderByIdDesc("2019-07-07 14:41:39:998", "2019-07-07 16:33:29:175", PageRequest.of(0, 3)).forEach(System.out::println);
    }

    /**
     * 模糊匹配查询对应的是QueryString方法这个可以参考:<a>https://www.jianshu.com/p/9f6f7f67df4e</a>
     */
    @Test
    public void nativeSearchQuery() {
        System.out.println("***********************模糊查询***********************");
        // 构建查询对象
        NativeSearchQuery query = new NativeSearchQueryBuilder()
                .withQuery(QueryBuilders.queryStringQuery("sunny在学用docker搭建elasticsearch环境").defaultField("content"))
                .withPageable(PageRequest.of(0, 3))
                .build();

        elasticsearchTemplate.queryForList(query, Article.class).forEach(System.out::println);
    }

    /**
     * 删除文章 deleteAll()、delete() 这些方法类似不写了
     */
    @Test
    public void deleteDocumentById() {
        System.out.println("***********************根据id删除***********************");
        articleService.deleteById("1");
    }
}

可能遇到的问题

  • Caused by: java.lang.ClassNotFoundException: org.elasticsearch.action.admin.indices.mapping.put.PutMappingResponse

    出现这个问题是因为你选择的spring-boot-starter-data-elasticsearch版本没有对elasticsearch兼容,你找一个有PutMappingResponse的版本,我选择的是6.4.0

  • failed to load elasticsearch nodes : org.elasticsearch.index.mapper.MapperParsingException: analyzer [ik_smart] not found for field [name]

    出现这个问题说明你的elasticsearch没有安装ik插件,可以看我的elasticsearch-in-java

  • Constructor threw exception; nested exception is java.lang.IllegalArgumentException: Rejecting mapping update to [elastic] as the final mapping would have more than 1 type: [sunny, user]

    出现这个问题是以为你的索引elastic存在两个mapping,在elasticsearch-head删除索引重新开始

  • IllegalArgumentException[Parse failure at index [0] of [Sun Jul 07 06:41:39 UTC 2019]]

    出现这个问题主要是你设置了日期类型跟参数类型不对称导致,入参改为string即可,可以参考ArticleService#findArticlesByCreateTimeBetweenOrderByIdDesc是怎么处理的

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 162,710评论 4 376
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 68,839评论 2 308
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 112,295评论 0 255
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,776评论 0 223
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 53,198评论 3 297
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 41,074评论 1 226
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 32,200评论 2 322
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,986评论 0 214
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,733评论 1 250
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,877评论 2 254
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,348评论 1 265
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,675评论 3 265
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,393评论 3 246
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,209评论 0 9
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,996评论 0 201
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 36,212评论 2 287
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 36,003评论 2 280

推荐阅读更多精彩内容