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是怎麼處理的

最後

如果你想了解更多的文章可以微信搜索zhaoyx92,或者掃碼關注.別抱有太高期望,更新很慢的
zhaoyx92

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章