1、建SpringBoot项目:elaticsearch_springboot

2、改pom

注意如果你使用自动引入依赖,默认使用的springboot版本为最新的,需要将版本改低一点!!!

<?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.2.5.RELEASE</version>
        <relativePath/>
    </parent>
    <groupId>com.example</groupId>
    <artifactId>elaticsearch</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>elasticsearch</name>
    <description>Demo project for Spring Boot</description>

    <properties>
        <java.version>1.8</java.version>
    </properties>

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

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

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

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <excludes>
                        <exclude>
                            <groupId>org.projectlombok</groupId>
                            <artifactId>lombok</artifactId>
                        </exclude>
                    </excludes>
                </configuration>
            </plugin>
        </plugins>
    </build>

</project>

3、配置类

两种方式:推荐第二种
方式一:spring-data(2~3.x版本配置)

spring:
  data:
    elasticsearch:
      cluster-nodes: 192.168.77.138:9300

方式二: spring-data(新版本推荐配置)

/**
     * @Author: xj0927
     * @Description: RestHighLevelClient 客户端配置
     * @Date Created in 2020-12-30 14:05
     * @Modified By:
     */
@Configuration
public class RestClientConfig extends AbstractElasticsearchConfiguration {

    @Override
    @Bean
    public RestHighLevelClient elasticsearchClient() {
        final ClientConfiguration clientConfiguration = ClientConfiguration.builder()
            .connectedTo("192.168.77.138:9200")  //===>与kibana客户端类型都是restful分格,都是连接9200端口
            .build();
        return RestClients.create(clientConfiguration).rest();
    }

}

4、实体类

ES操作相关的实体类,可以只需要业务实体类的某一些字段

@Document: 代表一个文档记录

  • indexName: 用来指定索引名称
  • type: 用来指定索引类型

@Id: 用来将对象中id和ES中_id映射

@Field: 用来指定ES中的字段对应Mapping

  • type: 用来指定ES中存储类型
  • analyzer: 用来指定使用哪种分词器
/**
 * [用在类上]作用: 将Emp的对象映射成ES中一条json格式文档
 * 			indexName  : 用来指定这个对象的转为json文档存入那个索引中 要求:ES服务器中之前不能存在此索引名
 * 			type     : 用来指定在当前这个索引下创建的类型名称
 */
@Document(indexName = "ems", type = "emp")
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Emp {

    @Id //与ES中_id进行映射
    private String id;

    /**
     * @Description: 用在属性上 代表mapping中一个属性 一个字段
     * type:属性 用来指定字段类型 analyzer:指定分词器
     * @Author: xj0927
     * @Date Created in 2020/12/30 14:38
     */
    @Field(type = FieldType.Text, analyzer = "ik_max_word")
    private String name;

    @Field(type = FieldType.Integer)
    private Integer age;

    @Field(type = FieldType.Date)
    @JsonFormat(pattern = "yyyy-MM-dd")
    private Date bir;

    @Field(type = FieldType.Text, analyzer = "ik_max_word")
    private String content;

    @Field(type = FieldType.Keyword)
    private String address;
}

5、通用接口

对一些简单的crud操作,可以使用 ElasticSearchRespositoy 接口

/**
 * @Author: xj0927
 * @Description: ElasticsearchRepository :ES提供的操作CRUD接口
 *                  第一个参数:指定对象类型
 *                  第二个参数:ID类型
 * @Date Created in 2020-12-30 14:23
 * @Modified By:
 */
public interface EmpRepository extends ElasticsearchRepository<Emp,String> {
}

6、ElasticSearchRespositoy 实现基本crud

通过最定义接口继承ES提供的ElasticsearchRepository接口来实现

索引or更新一条记录

这种方式根据实体类中中配置自动在ES创建索引,类型以及映射

  • 不传入id表示添加操作,会自动生成id
  • 传入id,ES中有此id表示更新,没有表示添加
@SpringBootTest(classes = Application.class)
@RunWith(SpringRunner.class)
public class TestSpringBootDataEs {
    @Autowired
    private BookRepository bookRespistory;
    /**
     * 添加索引和更新索引 id 存在更新 不存在添加
     */
    @Test
    public void testSaveOrUpdate(){
        Book book = new Book();
        book.setId("21");
        book.setName("小陈");
        book.setCreateDate(new Date());
        book.setAuthor("李白");
        book.setContent("这是中国的好人,这真的是一个很好的人,李白很狂");
        bookRespistory.save(book);
    }
}

删除一条记录

两种方式:根据id,根据对象属性值

@Test
public void testDelete(){
    Book book = new Book();
    book.setId("21");
    bookRespistory.delete(book);
}

查询
/**
*  查询一个
*/
@Test
public void testFindOne(){
    Optional<Book> byId = bookRespistory.findById("21");
    System.out.println(byId.get());
}

/**
*  查询所有
*/
@Test
public void testFindAll(){
    Iterable<Book> books = bookRespistory.findAll();
    for (Book book : books) {
        System.out.println(book);
    }
}

查询并排序
@Test
public void testFindAllOrder(){
    Iterable<Book> books = bookRespistory.findAll(Sort.by(Sort.Order.asc("createDate")));
    books.forEach(book -> System.out.println(book) );
}

自定义基本查询

通过 ElasticsearchRepository 接口除了ES提供的api还可以在自定义接口中自定义一些查询的方法

Keyword

Sample

Elasticsearch Query String

And:同时满足

findByNameAndPrice

{"bool" : {"must" : [ {"field" : {"name" : "?"}}, {"field" : {"price" : "?"}} ]}}

Or:满足其一

findByNameOrPrice

{"bool" : {"should" : [ {"field" : {"name" : "?"}}, {"field" : {"price" : "?"}} ]}}

Is:据某个字段查询

findByName

{"bool" : {"must" : {"field" : {"name" : "?"}}}}

Not:不包含

findByNameNot

{"bool" : {"must_not" : {"field" : {"name" : "?"}}}}

Between:某个字段在某个范围之间

findByPriceBetween

{"bool" : {"must" : {"range" : {"price" : {"from" : ?,"to" : ?,"include_lower" : true,"include_upper" : true}}}}}

LessThanEqual:<=

findByPriceLessThanEqual

{"bool" : {"must" : {"range" : {"price" : {"from" : null,"to" : ?,"include_lower" : true,"include_upper" : true}}}}}

GreaterThanEqual:>=

findByPriceGreaterThanEqual

{"bool" : {"must" : {"range" : {"price" : {"from" : ?,"to" : null,"include_lower" : true,"include_upper" : true}}}}}

Before:…之前

findByPriceBefore

{"bool" : {"must" : {"range" : {"price" : {"from" : null,"to" : ?,"include_lower" : true,"include_upper" : true}}}}}

After:…之后

findByPriceAfter

{"bool" : {"must" : {"range" : {"price" : {"from" : ?,"to" : null,"include_lower" : true,"include_upper" : true}}}}}

Like:模糊匹配

findByNameLike

{"bool" : {"must" : {"field" : {"name" : {"query" : "?*","analyze_wildcard" : true}}}}}

StartingWith

findByNameStartingWith

{"bool" : {"must" : {"field" : {"name" : {"query" : "?*","analyze_wildcard" : true}}}}}

EndingWith

findByNameEndingWith

{"bool" : {"must" : {"field" : {"name" : {"query" : "*?","analyze_wildcard" : true}}}}}

Contains/Containing

findByNameContaining

{"bool" : {"must" : {"field" : {"name" : {"query" : "**?**","analyze_wildcard" : true}}}}}

In

findByNameIn (Collectionnames)

{"bool" : {"must" : {"bool" : {"should" : [ {"field" : {"name" : "?"}}, {"field" : {"name" : "?"}} ]}}}}

NotIn

findByNameNotIn (Collectionnames)

{"bool" : {"must_not" : {"bool" : {"should" : {"field" : {"name" : "?"}}}}}}

Near

findByStoreNear

Not Supported Yet !

True

findByAvailableTrue

{"bool" : {"must" : {"field" : {"available" : true}}}}

False

findByAvailableFalse

{"bool" : {"must" : {"field" : {"available" : false}}}}

OrderBy

findByAvailable TrueOrderByNameDesc

{"sort" : [{ "name" : {"order" : "desc"} }],"bool" : {"must" : {"field" : {"available" : true}}}}

举一些例子:

public interface BookRepository extends ElasticsearchRepository<Book,String> {

    //根据作者查询
    List<Book> findByAuthor(String keyword);

    //根据内容查询
    List<Book> findByContent(String keyword);

    //根据内容和名字查
    List<Book> findByNameAndContent(String name,String content);

    //根据内容或名称查询
    List<Book> findByNameOrContent(String name,String content);

    //范围查询
    List<Book> findByPriceBetween(Double start,Double end);

    //查询名字以xx开始的
    List<Book>  findByNameStartingWith(String name);

    //查询某个字段值是否为false
    List<Book>  findByNameFalse();

    //.......
    
    //根据名字查询,然后 根据Pageable 参数进行分页
    //调用时:PageRequest page = PageRequest.of(0, 2);
    List<Emp> findByContent(String name, Pageable pageable);
}

7、RestHighLevelClient 实现复杂查询

分页查询并排序
@Test
public void testSearchPage() throws IOException {
    //查询请求
    SearchRequest searchRequest = new SearchRequest();

    //查询条件
    SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
    sourceBuilder.from(0).size(2).sort("age", SortOrder.ASC).query(QueryBuilders.matchAllQuery());

    //去哪个索引/类型查询
    searchRequest.indices("ems").types("emp").source(sourceBuilder);

    //====>查询方法
    SearchResponse search = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);

    SearchHit[] hits = search.getHits().getHits();
    for (SearchHit hit : hits) {
        //字符串格式展示
        System.out.println(hit.getSourceAsString());
    }
}

高亮查询
@Test
public void testLight() throws IOException {

    //集合存放查找到的数据
    List<Emp> list = new ArrayList<>();

    //查询请求
    SearchRequest searchRequest = new SearchRequest();

    //查询条件[对象]
    SearchSourceBuilder builder = new SearchSourceBuilder();

    //高亮配置
    HighlightBuilder highlightBuilder = new HighlightBuilder();
    highlightBuilder.field("*").requireFieldMatch(false).preTags("<span style='color:red'>").postTags("</span>");

    //具体按...查询
    builder.from(0).size(2)
        .sort("age", SortOrder.DESC)
        .highlighter(highlightBuilder)
        .query(QueryBuilders.multiMatchQuery("小黑喜欢小红", "name", "content"));

    //从哪个索引/类型查找
    searchRequest.indices("ems").types("emp").source(builder);

    //===>查询方法
    SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);

    System.out.println("符合条件总数:" + searchResponse.getHits().getTotalHits());
    System.out.println("最大得分:" + searchResponse.getHits().getMaxScore());

    System.out.println("每条文档详细信息===>");
    SearchHit[] hits = searchResponse.getHits().getHits();
    for (SearchHit s :hits) {
        //===>原文档部分
        System.out.println(s.getSourceAsMap());
        //返回对象
        Emp emp = new Emp();
        emp.setId((String) s.getSourceAsMap().get("id"));
        emp.setName((String) s.getSourceAsMap().get("name"));
        emp.setContent((String) s.getSourceAsMap().get("content"));
        emp.setAddress((String) s.getSourceAsMap().get("address"));
        emp.setAge((Integer) s.getSourceAsMap().get("age"));

        //==>高亮部分
        Map<String, HighlightField> highlightFields = s.getHighlightFields();
        if(highlightFields.containsKey("name")){
            emp.setName(highlightFields.get("name").fragments()[0].toString());
        }
        if(highlightFields.containsKey("content")){
            emp.setContent(highlightFields.get("content").fragments()[0].toString());
        }
        list.add(emp);
    }
    //===>存入对象的文档[包括高亮部分]
    System.out.println("===>存入对象的文档[包括高亮部分]");
    list.forEach(emp -> {
        System.out.println(emp);
    });

}

springboot ES6 springboot es6.8.11_springboot ES6

为什么要分开拿原文档和高亮部分:

springboot ES6 springboot es6.8.11_springboot ES6_02