Elasticsearch(一)

124 阅读4分钟

一、安装和配置

1.安装

elasticsearch默认不允许以root账号运行,所以创建一个用户 创建用户:useradd tracy 设置密码:passwd xxx 此时可能由于密码过于简单提示,直接再输入一次回车即可

切换用户:su - tracy 上传安装包

切回root用户,分配tracy用户权限: chown tracy:tracy elasticsearch-6.3.0.tar.gz chmod 755 elasticsearch-6.3.0.tar.gz

image.png

解压之后的目录:

image.png

2.配置

如果服务器内存不够,修改config目录下的jvm.options文件: image.png

指定索引库和日志文件、设置允许所有ip访问(默认不允许远程服务器访问): image.png

建立对应的文件夹 image.png

3.启动

image.png

启动中出现以下两个错误: image.png

解决: 线程数不够 修改文件 vim /etc/security/limits.d/90-nproc.conf * soft nproc 1024--->* soft nproc 4096

文件权限不足 切换回root用户,修改文件/etc/security/limits.conf 添加内容:

soft nofile 65536
hard nofile 131072
soft nproc 4096
hard nproc 4096

进程虚拟内存 vm.max_map_count:限制一个进程可以拥有的VMA(虚拟内存区域)的数量,继续修改配置文件: vim /etc/sysctl.conf 添加内容:vm.max_map_count=655360 执行命令:sysctl -p

安装分词器到elasticsearch/plugins目录下 unzip elasticsearch-analysis-ik-6.3.0.zip -d ik-analyzer

二、客户端

Low Level Rest Client是低级别封装,提供一些基础功能,但更灵活

High Level Rest Client,是在Low Level Rest Client基础上进行的高级别封装,功能更丰富和完善,而且API会变的简单

三、Spring Data Elasticsearch

application.yml

spring:
  data:
    elasticsearch:
      cluster-name: elasticsearch
      cluster-nodes: 120.111.61.110:9300

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.0.6.RELEASE</version>
		<relativePath/> <!-- lookup parent from repository -->
	</parent>
	<groupId>com.hcx</groupId>
	<artifactId>elasticsearch</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<name>elasticsearch</name>
	<description>Demo project for Spring Boot</description>

	<properties>
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
		<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
		<java.version>1.8</java.version>
	</properties>

	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-data-elasticsearch</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter</artifactId>
		</dependency>

		<dependency>
			<groupId>org.projectlombok</groupId>
			<artifactId>lombok</artifactId>
			<version>1.18.6</version>
		</dependency>

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
			<exclusions>
				<exclusion>
					<groupId>org.junit.vintage</groupId>
					<artifactId>junit-vintage-engine</artifactId>
				</exclusion>
			</exclusions>
		</dependency>
	</dependencies>

	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
		</plugins>
	</build>
</project>

Item:

package com.hcx.pojo;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.data.annotation.Id;
import org.springframework.data.elasticsearch.annotations.Document;
import org.springframework.data.elasticsearch.annotations.Field;
import org.springframework.data.elasticsearch.annotations.FieldType;

/**
 * Created by hongcaixia on 2020/2/27.
 */
@Data
@Document(indexName = "item",type = "docs",shards = 1,replicas = 0)
@NoArgsConstructor
@AllArgsConstructor
public class Item {
    @Id
    Long id;
    @Field(type = FieldType.Text,analyzer = "ik_max_word")
    String title; //标题
    @Field(type = FieldType.Keyword)
    String category;// 分类
    @Field(type = FieldType.Keyword)
    String brand; // 品牌
    @Field(type = FieldType.Double)
    Double price; // 价格
    @Field(type = FieldType.Keyword,index = false)
    String images; // 图片地址
}

ItemRepository:

package com.hcx.repository;

import com.hcx.pojo.Item;
import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;

import java.util.List;

/**
 * Created by hongcaixia on 2020/2/28.
 */
public interface ItemRepository extends ElasticsearchRepository<Item,Long>{
    List<Item> findByTitle(String title);
    List<Item> findByPriceBetween(Double d1,Double d2);
}

ElasticsearchTest:

package com.hcx.elasticsearch;

import com.hcx.pojo.Item;
import com.hcx.repository.ItemRepository;
import org.elasticsearch.index.query.MatchQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.aggregations.Aggregation;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.bucket.terms.StringTerms;
import org.elasticsearch.search.aggregations.metrics.avg.InternalAvg;
import org.elasticsearch.search.sort.SortBuilders;
import org.elasticsearch.search.sort.SortOrder;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.data.elasticsearch.core.ElasticsearchTemplate;
import org.springframework.data.elasticsearch.core.aggregation.AggregatedPage;
import org.springframework.data.elasticsearch.core.query.FetchSourceFilter;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.test.context.junit4.SpringRunner;

import java.util.*;

/**
 * Created by hongcaixia on 2020/2/27.
 */
@SpringBootTest
@RunWith(SpringRunner.class)
public class ElasticsearchTest {

    @Autowired
    private ElasticsearchTemplate elasticsearchTemplate;

    @Autowired
    private ItemRepository itemRepository;

    @Test
    public void testIndex() {
        elasticsearchTemplate.createIndex(Item.class);
        elasticsearchTemplate.putMapping(Item.class);
    }

    /**
     * 新增/更新
     */
    @Test
    public void testCreate() {
        Item item = new Item(1L, "小米10", "手机", "小米", 3999.00,
                "http:/image.myshoppingmall.com/1.jpg");
        itemRepository.save(item);
    }

    /**
     * 批量新增
     */
    @Test
    public void indexList() {
        List<Item> list = new ArrayList<>();
        list.add(new Item(2L, "坚果pro2", " 手机", "锤子", 3099.00, "http://image.myshoppingmall.com/2.jpg"));
        list.add(new Item(3L, "华为META20", " 手机", "华为", 4399.00, "http://image.myshoppingmall.com/3.jpg"));
        // 接收对象集合,实现批量新增
        itemRepository.saveAll(list);
    }

    /**
     * 删除
     */
    @Test
    public void testDelete() {
        Item item = new Item(1L, "小米10", "手机", "小米", 3999.00,
                "http:/image.myshoppingmall.com/1.jpg");
        itemRepository.delete(item);
    }

    /**
     * 根据id查找单条
     */
    @Test
    public void testFind() {
        Optional<Item> item = itemRepository.findById(1l);
        System.out.println(item.get());
    }

    /**
     * 查询多条并排序
     */
    @Test
    public void testFindAll() {
        Iterable<Item> items = itemRepository.findAll(Sort.by("price").descending());
        items.forEach(System.out::println);
    }

    /**
     * 根据某个字段查询
     */
    @Test
    public void testFindByTitle() {
        List<Item> items = itemRepository.findByTitle("手机");
        items.forEach(System.out::println);
    }

    @Test
    public void testFindByPriceBetween() {
        List<Item> items = itemRepository.findByPriceBetween(3099d, 4999d);
        items.forEach(System.out::println);
    }

    /**
     * 使用查询构建器查询
     */
    @Test
    public void testSearch() {
        //使用查询构建器工具构建查询条件
        MatchQueryBuilder queryBuilder = QueryBuilders.matchQuery("title", "手机");
        Iterable<Item> items = itemRepository.search(queryBuilder);
        items.forEach(System.out::println);
    }

    /**
     * 使用自定义查询构建器
     */
    @Test
    public void testNative() {
        //构建自定义查询构建器
        NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder();
        //添加基本的查询条件
        queryBuilder.withQuery(QueryBuilders.matchQuery("title", "手机"));
        //执行查询获取分页结果集
        Page<Item> itemPage = itemRepository.search(queryBuilder.build());
        System.out.println(itemPage.getTotalPages());
        System.out.println(itemPage.getTotalElements());
        itemPage.getContent().forEach(System.out::println);
    }

    /**
     * 分页
     */
    @Test
    public void testPage() {
        //构建自定义查询构建器
        NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder();
        //添加基本的查询条件
        queryBuilder.withQuery(QueryBuilders.matchQuery("title", "手机"));
        //添加分页条件,页码从零开始
        queryBuilder.withPageable(PageRequest.of(0, 2));
        //执行查询获取分页结果集
        Page<Item> itemPage = itemRepository.search(queryBuilder.build());
        System.out.println(itemPage.getTotalPages());
        System.out.println(itemPage.getTotalElements());
        itemPage.getContent().forEach(System.out::println);
    }

    /**
     * 排序
     */
    @Test
    public void testSort() {
        //构建自定义查询构建器
        NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder();
        //添加基本的查询条件
        queryBuilder.withQuery(QueryBuilders.matchQuery("title", "手机"));
        //根据价格降序
        queryBuilder.withSort(SortBuilders.fieldSort("price").order(SortOrder.DESC));
        //执行查询获取分页结果集
        Page<Item> itemPage = itemRepository.search(queryBuilder.build());
        System.out.println(itemPage.getTotalPages());
        System.out.println(itemPage.getTotalElements());
        itemPage.getContent().forEach(System.out::println);
    }

    @Test
    public void testAggregation() {
        //构建自定义查询构建器
        NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder();
        //添加聚合
        queryBuilder.addAggregation(AggregationBuilders.terms("brandAgg").field("brand"));
        //添加结果集过滤,不包含任何字段
        queryBuilder.withSourceFilter(new FetchSourceFilter(new String[]{}, null));
        //执行聚合查询
        AggregatedPage<Item> itemPage = (AggregatedPage<Item>) itemRepository.search(queryBuilder.build());
        //解析聚合结果集,根据聚合的类型及字段类型强转 brand:字符串类型;聚合类型:词条聚合
        //通过聚合名称brandAgg 获取聚合对象
        StringTerms brandAgg = (StringTerms) itemPage.getAggregation("brandAgg");
        List<StringTerms.Bucket> buckets = brandAgg.getBuckets();
        buckets.forEach(bucket -> {
            //聚合名称
            System.out.println(bucket.getKeyAsString());
            //记录数
            System.out.println(bucket.getDocCount());
        });
    }

    @Test
    public void testSubAggregation() {
        //构建自定义查询构建器
        NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder();
        //添加聚合
        queryBuilder.addAggregation(AggregationBuilders.terms("brandAgg").field("brand")
                .subAggregation(AggregationBuilders.avg("price_avg").field("price")));

        //添加结果集过滤,不包含任何字段
        queryBuilder.withSourceFilter(new FetchSourceFilter(new String[]{}, null));
        //执行聚合查询
        AggregatedPage<Item> itemPage = (AggregatedPage<Item>) itemRepository.search(queryBuilder.build());
        //解析聚合结果集,根据聚合的类型及字段类型强转 brand:字符串类型;聚合类型:词条聚合
        //通过聚合名称brandAgg 获取聚合对象
        StringTerms brandAgg = (StringTerms) itemPage.getAggregation("brandAgg");
        List<StringTerms.Bucket> buckets = brandAgg.getBuckets();
        buckets.forEach(bucket -> {
            //聚合名称
            System.out.println(bucket.getKeyAsString());
            //记录数
            System.out.println(bucket.getDocCount());
            //子聚合map集合:key:聚合名称  value:子聚合对象
            Map<String, Aggregation> stringAggregationMap = bucket.getAggregations().asMap();
            InternalAvg priceAvg = (InternalAvg) stringAggregationMap.get("price_avg");
            System.out.println(priceAvg.getValue());
        });
    }
}