Spring-data ElasticSearch的使用

1.maven坐标的导入
<dependency>
    <groupId>org.elasticsearch</groupId>
    <artifactId>elasticsearch</artifactId>
    <version>2.4.0</version>
</dependency>
<dependency>
    <groupId>org.springframework.data</groupId>
    <artifactId>spring-data-elasticsearch</artifactId>
    <version>2.0.4.RELEASE</version>
</dependency>
2.准备测试类 Article(添加spring data elasticsearch 注解)

@Document : 文档对象(索引信息index,文档类型mapping)
@Id : 文档主键,唯一标识
@Field : 每个文档的域配置

index = FieldIndex.not_analyzed : 不分词
index = FieldIndex.analyzed : 分词
index = FieldIndex.not : 不创建索引
analyzer = “ik” : 指定使用的分词器
store = true : 是否保存
searchAnalyzer = “ik” : 查询所使用的分词器
type = FieldType.String : 指定域的类型

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.FieldIndex;
import org.springframework.data.elasticsearch.annotations.FieldType;

@Document(indexName = "blog3", type = "article")
public class Article {
    @Id
    @Field(index = FieldIndex.not_analyzed, store = true, type = FieldType.Integer)
    private Integer id;
    @Field(index = FieldIndex.analyzed, analyzer = "ik", store = true, searchAnalyzer = "ik", type = FieldType.String)
    private String title;
    @Field(index = FieldIndex.analyzed, analyzer = "ik", store = true, searchAnalyzer = "ik", type = FieldType.String)
    private String content;
    public Integer getId() {
        return id;
    }
    public void setId(Integer id) {
        this.id = id;
    }
    public String getTitle() {
        return title;
    }
    public void setTitle(String title) {
        this.title = title;
    }
    public String getContent() {
        return content;
    }
    public void setContent(String content) {
        this.content = content;
    }
    @Override
    public String toString() {
        return "Article [id=" + id + ", title=" + title + ", content="
                + content + "]";
    }
}
3.spring配置文件配置ElasticSearch
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:elasticsearch="http://www.springframework.org/schema/data/elasticsearch"
    xsi:schemaLocation="
        http://www.springframework.org/schema/beans 
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context 
        http://www.springframework.org/schema/context/spring-context.xsd
        http://www.springframework.org/schema/data/elasticsearch
        http://www.springframework.org/schema/data/elasticsearch/spring-elasticsearch-1.0.xsd ">

    <!-- 扫描DAO包 自动创建实现 -->
    <elasticsearch:repositories base-package="cn.itcast.dao" />

    <!-- 扫描Service包 -->
    <context:component-scan base-package="cn.itcast.service" />

    <!-- 配置elasticsearch 连接 -->
    <elasticsearch:transport-client id="client" cluster-nodes="localhost:9300" />

    <!-- spring data elasticsearch DAO 必须依赖 elasticsearchTemplate  -->
    <bean id="elasticsearchTemplate" 
        class="org.springframework.data.elasticsearch.core.ElasticsearchTemplate">
        <constructor-arg name="client" ref="client" />
    </bean>

</beans>
4.编写dao的spring-data elasticsearch接口
import java.util.List;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;

import cn.itcast.domain.Article;

public interface ArticleRepository extends
        ElasticsearchRepository<Article, Integer> {

    List<Article> findByTitle(String title);

    Page<Article> findByTitle(String title, Pageable pageable);

}
5.常见错误分析

错误一 :

 java.lang.NoClassDefFoundError:org/springframework/core/ResolvableTypeProvider 

错误原因: 导报冲突
解决: spring 导包版本要一致,提升 spring 依赖版本 4.1.7 提升 4.2.8 (最高)
错误二:

MapperParsingException[No type specified for field [title]]

错误三:

Caused by: java.lang.AbstractMethodError: org.springframework.data.jpa.repos

原因:是spring-data-jpa.jar的版本和spring-data-commons-core.jar的版本不匹配所造成的,spring-data-commons-core.jar的版本过高了.
在发生异常的时候我的版本是:spring-data-jpa-1.0.2.RELEASE.jar和spring-data-commons-core-1.3.0.M1.jar
更改后:spring-data-jpa-1.0.2.RELEASE.jar和spring-data-commons-core-1.1.0.RELEASE.jar (OK)
错误原因: 实体类中未指定域的类型
解决: 在是类的字段中添加注解@Field(type = FieldType.String)
问题四:
ElasticSearch使用的是jackson来进行对象序列化的,所以有些时候可能会造成双向关联的对象,在转json的时候,会相互引用,造成栈内存溢出,需要使用@JsonIgnore来排除双向引用的字段

6.原始Elasticsearch用法
import java.io.IOException;
import java.net.InetAddress;
import java.util.Iterator;
import java.util.Map;
import java.util.concurrent.ExecutionException;
import org.elasticsearch.action.admin.indices.mapping.put.PutMappingRequest;
import org.elasticsearch.action.delete.DeleteRequest;
import org.elasticsearch.action.search.SearchRequestBuilder;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.Client;
import org.elasticsearch.client.Requests;
import org.elasticsearch.client.transport.TransportClient;
import org.elasticsearch.common.text.Text;
import org.elasticsearch.common.transport.InetSocketTransportAddress;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentFactory;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.highlight.HighlightField;
import org.junit.Test;

import cn.itcast.elasticsearch.domain.Article;

import com.fasterxml.jackson.databind.ObjectMapper;

// ElasticSearch 测试程序 
public class ElasticSearchTest {

    @Test
    // 直接在ElasticSearch中建立文档,自动创建索引
    public void demo1() throws IOException {
        // 创建连接搜索服务器对象
        Client client = TransportClient
                .builder()
                .build()
                .addTransportAddress(
                        new InetSocketTransportAddress(InetAddress
                                .getByName("127.0.0.1"), 9300));
        // 描述json 数据
        /*
         * {id:xxx, title:xxx, content:xxx}
         */
        XContentBuilder builder = XContentFactory
                .jsonBuilder()
                .startObject()
                .field("id", 1)
                .field("title", "ElasticSearch是一个基于Lucene的搜索服务器")
                .field("content",
                        "它提供了一个分布式多用户能力的全文搜索引擎,基于RESTful web接口。Elasticsearch是用Java开发的,并作为Apache许可条款下的开放源码发布,是当前流行的企业级搜索引擎。设计用于云计算中,能够达到实时搜索,稳定,可靠,快速,安装使用方便。")
                .endObject();
        // 建立文档对象
        client.prepareIndex("blog1", "article", "1").setSource(builder).get();

        // 关闭连接
        client.close();
    }

    @Test
    // 搜索在elasticSearch中创建文档对象
    public void demo2() throws IOException {
        // 创建连接搜索服务器对象
        Client client = TransportClient
                .builder()
                .build()
                .addTransportAddress(
                        new InetSocketTransportAddress(InetAddress
                                .getByName("127.0.0.1"), 9300));
        // 搜索数据
        // get() === execute().actionGet()
        SearchResponse searchResponse = client.prepareSearch("blog1")
                .setTypes("article").setQuery(QueryBuilders.matchAllQuery())
                .get();
        printSearchResponse(searchResponse);

        // 关闭连接
        client.close();
    }

    @Test
    // 各种查询使用
    public void demo3() throws IOException {
        // 创建连接搜索服务器对象
        Client client = TransportClient
                .builder()
                .build()
                .addTransportAddress(
                        new InetSocketTransportAddress(InetAddress
                                .getByName("127.0.0.1"), 9300));
        // 搜索数据
        // get() === execute().actionGet()
        // SearchResponse searchResponse = client.prepareSearch("blog1")
        // .setTypes("article")
        // .setQuery(QueryBuilders.queryStringQuery("全面")).get();

        // SearchResponse searchResponse = client.prepareSearch("blog1")
        // .setTypes("article")
        // .setQuery(QueryBuilders.wildcardQuery("content", "*全文*")).get();

        SearchResponse searchResponse = client.prepareSearch("blog2")
                .setTypes("article")
                .setQuery(QueryBuilders.termQuery("content", "搜索")).get();
        printSearchResponse(searchResponse);

        // 关闭连接
        client.close();
    }

    private void printSearchResponse(SearchResponse searchResponse) {
        SearchHits hits = searchResponse.getHits(); // 获取命中次数,查询结果有多少对象
        System.out.println("查询结果有:" + hits.getTotalHits() + "条");
        Iterator<SearchHit> iterator = hits.iterator();
        while (iterator.hasNext()) {
            SearchHit searchHit = iterator.next(); // 每个查询对象
            System.out.println(searchHit.getSourceAsString()); // 获取字符串格式打印
            System.out.println("title:" + searchHit.getSource().get("title"));
        }
    }

    @Test
    // 索引操作
    public void demo4() throws IOException {
        // 创建连接搜索服务器对象
        Client client = TransportClient
                .builder()
                .build()
                .addTransportAddress(
                        new InetSocketTransportAddress(InetAddress
                                .getByName("127.0.0.1"), 9300));

        // 创建索引
        client.admin().indices().prepareCreate("blog2").get();

        // 删除索引
        client.admin().indices().prepareDelete("blog2").get();

        // 关闭连接
        client.close();
    }

    @Test
    // 映射操作
    public void demo5() throws IOException, InterruptedException,
            ExecutionException {
        // 创建连接搜索服务器对象
        Client client = TransportClient
                .builder()
                .build()
                .addTransportAddress(
                        new InetSocketTransportAddress(InetAddress
                                .getByName("127.0.0.1"), 9300));

        // 添加映射
        XContentBuilder builder = XContentFactory.jsonBuilder().startObject()
                .startObject("article").startObject("properties")
                .startObject("id").field("type", "integer")
                .field("store", "yes").endObject().startObject("title")
                .field("type", "string").field("store", "yes")
                .field("analyzer", "ik").endObject().startObject("content")
                .field("type", "string").field("store", "yes")
                .field("analyzer", "ik").endObject().endObject().endObject()
                .endObject();

        PutMappingRequest mapping = Requests.putMappingRequest("blog2")
                .type("article").source(builder);
        client.admin().indices().putMapping(mapping).get();

        // 关闭连接
        client.close();
    }

    @Test
    // 文档相关操作
    public void demo6() throws IOException, InterruptedException,
            ExecutionException {
        // 创建连接搜索服务器对象
        Client client = TransportClient
                .builder()
                .build()
                .addTransportAddress(
                        new InetSocketTransportAddress(InetAddress
                                .getByName("127.0.0.1"), 9300));
        // 描述json 数据
        /*
         * {id:xxx, title:xxx, content:xxx}
         */
        Article article = new Article();
        article.setId(2);
        article.setTitle("搜索工作其实很快乐");
        article.setContent("我们希望我们的搜索解决方案要快,我们希望有一个零配置和一个完全免费的搜索模式,我们希望能够简单地使用JSON通过HTTP的索引数据,我们希望我们的搜索服务器始终可用,我们希望能够一台开始并扩展到数百,我们要实时搜索,我们要简单的多租户,我们希望建立一个云的解决方案。Elasticsearch旨在解决所有这些问题和更多的问题。");

        ObjectMapper objectMapper = new ObjectMapper();

        // 建立文档
        // client.prepareIndex("blog2", "article", article.getId().toString())
        // .setSource(objectMapper.writeValueAsString(article)).get();

        // 修改文档
        // client.prepareUpdate("blog2", "article", article.getId().toString())
        // .setDoc(objectMapper.writeValueAsString(article)).get();

        // 修改文档
        // client.update(
        // new UpdateRequest("blog2", "article", article.getId()
        // .toString()).doc(objectMapper
        // .writeValueAsString(article))).get();

        // 删除文档
        // client.prepareDelete("blog2", "article", article.getId().toString())
        // .get();

        // 删除文档
        client.delete(
                new DeleteRequest("blog2", "article", article.getId()
                        .toString())).get();

        // 关闭连接
        client.close();
    }

    @Test
    // 批量查询100条记录
    public void demo7() throws IOException, InterruptedException,
            ExecutionException {
        // 创建连接搜索服务器对象
        Client client = TransportClient
                .builder()
                .build()
                .addTransportAddress(
                        new InetSocketTransportAddress(InetAddress
                                .getByName("127.0.0.1"), 9300));

        ObjectMapper objectMapper = new ObjectMapper();

        for (int i = 1; i <= 100; i++) {
            // 描述json 数据
            Article article = new Article();
            article.setId(i);
            article.setTitle(i + "搜索工作其实很快乐");
            article.setContent(i
                    + "我们希望我们的搜索解决方案要快,我们希望有一个零配置和一个完全免费的搜索模式,我们希望能够简单地使用JSON通过HTTP的索引数据,我们希望我们的搜索服务器始终可用,我们希望能够一台开始并扩展到数百,我们要实时搜索,我们要简单的多租户,我们希望建立一个云的解决方案。Elasticsearch旨在解决所有这些问题和更多的问题。");

            // 建立文档
            client.prepareIndex("blog2", "article", article.getId().toString())
                    .setSource(objectMapper.writeValueAsString(article)).get();
        }
        // 关闭连接
        client.close();
    }

    @Test
    // 分页搜索
    public void demo8() throws IOException {
        // 创建连接搜索服务器对象
        Client client = TransportClient
                .builder()
                .build()
                .addTransportAddress(
                        new InetSocketTransportAddress(InetAddress
                                .getByName("127.0.0.1"), 9300));
        // 搜索数据
        // get() === execute().actionGet()
        SearchRequestBuilder searchRequestBuilder = client
                .prepareSearch("blog2").setTypes("article")
                .setQuery(QueryBuilders.matchAllQuery());

        // 查询第2页数据,每页20条
        searchRequestBuilder.setFrom(20).setSize(20);

        SearchResponse searchResponse = searchRequestBuilder.get();
        printSearchResponse(searchResponse);

        // 关闭连接
        client.close();
    }

    @Test
    // 高亮查询结果 处理 搜索
    public void demo9() throws IOException {
        // 创建连接搜索服务器对象
        Client client = TransportClient
                .builder()
                .build()
                .addTransportAddress(
                        new InetSocketTransportAddress(InetAddress
                                .getByName("127.0.0.1"), 9300));

        ObjectMapper objectMapper = new ObjectMapper();

        // 搜索数据
        SearchRequestBuilder searchRequestBuilder = client
                .prepareSearch("blog2").setTypes("article")
                .setQuery(QueryBuilders.termQuery("title", "搜索"));

        // 高亮定义
        searchRequestBuilder.addHighlightedField("title"); // 对title字段进行高亮
        searchRequestBuilder.setHighlighterPreTags("<em>"); // 前置元素
        searchRequestBuilder.setHighlighterPostTags("</em>");// 后置元素

        SearchResponse searchResponse = searchRequestBuilder.get();

        SearchHits hits = searchResponse.getHits(); // 获取命中次数,查询结果有多少对象
        System.out.println("查询结果有:" + hits.getTotalHits() + "条");
        Iterator<SearchHit> iterator = hits.iterator();
        while (iterator.hasNext()) {
            SearchHit searchHit = iterator.next(); // 每个查询对象

            // 将高亮处理后内容,替换原有内容 (原有内容,可能会出现显示不全 )
            Map<String, HighlightField> highlightFields = searchHit
                    .getHighlightFields();
            HighlightField titleField = highlightFields.get("title");

            // 获取到原有内容中 每个高亮显示 集中位置 fragment 就是高亮片段
            Text[] fragments = titleField.fragments();
            String title = "";
            for (Text text : fragments) {
                title += text;
            }
            // 将查询结果转换为对象
            Article article = objectMapper.readValue(
                    searchHit.getSourceAsString(), Article.class);

            // 用高亮后内容,替换原有内容
            article.setTitle(title);

            System.out.println(article);
        }

        // 关闭连接
        client.close();
    }
}
7.使用Spring data ElasticSearch来操作索引库
(1)扫描jpa包
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
    xmlns:elasticsearch="http://www.springframework.org/schema/data/elasticsearch"
    xsi:schemaLocation="http://www.springframework.org/schema/data/elasticsearch http://www.springframework.org/schema/data/elasticsearch/spring-elasticsearch-1.0.xsd
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">

    <!-- 扫描DAO包 自动创建实现 -->   
    <elasticsearch:repositories base-package="cn.itcast.bos.index" />

    <!-- 配置elasticsearch 连接 -->      
    <elasticsearch:transport-client id="client"
        cluster-nodes="localhost:9300" /> 

    <!-- spring data elasticsearch DAO 必须依赖 elasticsearchTemplate -->
    <bean id="elasticsearchTemplate"
        class="org.springframework.data.elasticsearch.core.ElasticsearchTemplate">
        <constructor-arg name="client" ref="client" /> 
    </bean>  

</beans>
(2)继承Repository接口
import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;
import cn.itcast.bos.domain.delivery.WayBill;

public interface WayBillIndexRepository extends ElasticsearchRepository<WayBill, Integer> {

}
测试(添加)
// 执行保存索引库
wayBillIndexRepository.save(entity);
测试(条件分页查询)
/**
     * 分页查询索引库
     */
    @Override
    public void findPage(WayBill wayBill, PageBean pageBean) {
        BoolQueryBuilder query = new BoolQueryBuilder();
        if (StringUtils.isNotBlank(wayBill.getWayBillNum())) {
            // 设置运单号条件
            QueryBuilder termQuery = new TermQueryBuilder("wayBillNum", wayBill.getWayBillNum());
            query.must(termQuery);
        }
        if (StringUtils.isNotBlank(wayBill.getSendAddress())) {
            // 设置发送地址条件
            BoolQueryBuilder boolQuery = new BoolQueryBuilder();
            QueryBuilder wildcardQuery = new WildcardQueryBuilder("sendAddress", "*" + wayBill.getSendAddress() + "*");
            QueryBuilder queryStringQuery = new QueryStringQueryBuilder(wayBill.getSendAddress()).field("sendAddress")
                    .defaultOperator(Operator.AND);
            boolQuery.should(wildcardQuery);
            boolQuery.should(queryStringQuery);
            query.must(boolQuery);
        }
        if (StringUtils.isNotBlank(wayBill.getRecAddress())) {
            // 设置接收地址条件
            BoolQueryBuilder boolQuery = new BoolQueryBuilder();
            QueryBuilder wildcardQuery = new WildcardQueryBuilder("recAddress", "*" + wayBill.getRecAddress() + "*");
            QueryBuilder queryStringQuery = new QueryStringQueryBuilder(wayBill.getRecAddress()).field("recAddress")
                    .defaultOperator(Operator.AND);
            boolQuery.should(wildcardQuery);
            boolQuery.should(queryStringQuery);
            query.must(boolQuery);
        }
        if (StringUtils.isNotBlank(wayBill.getSendProNum())) {
            // 设置产品类型条件
            QueryBuilder termQuery = new TermQueryBuilder("sendProNum", wayBill.getSendProNum());
            query.must(termQuery);
        }
        if (wayBill.getSignStatus() != null && wayBill.getSignStatus() != 0) {
            // 设置快递产品类型编号条件
            QueryBuilder termQuery = new TermQueryBuilder("signStatus", wayBill.getSignStatus());
            query.must(termQuery);
        }

        Page<WayBill> search = wayBillIndexRepository.search(query,
                new PageRequest(pageBean.getCurrentPage() - 1, pageBean.getPageSize()));
        pageBean.setRows(search.getContent());
        pageBean.setTotal(search.getTotalElements());
    }
  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
spring-data-elasticsearch官方教程文档提供了关于如何使用spring-data-elasticsearch框架进行Elasticsearch数据库操作的详细指导。该文档分为几个部分,包括介绍、快速入门、基本概念、查询构造器和复杂查询等。 文档的介绍部分简要介绍了spring-data-elasticsearch框架以及它提供的主要功能。快速入门部分通过一个简单的示例演示了如何配置spring-data-elasticsearch并进行基本的CRUD操作。该示例涵盖了创建索引、映射实体类、保存数据、查询数据以及删除数据。通过这个示例,读者可以迅速了解到spring-data-elasticsearch的基本用法。 基本概念部分详细介绍了spring-data-elasticsearch中的一些重要概念,包括实体类映射、索引操作、文档操作、字段映射、分页和排序等。这些概念对于深入理解spring-data-elasticsearch使用非常重要。 查询构造器部分介绍了spring-data-elasticsearch提供的查询构造器的使用方法。该部分通过实例演示了如何使用查询构造器进行基本查询、范围查询、模糊查询以及布尔查询等。读者可以通过这些示例快速掌握查询构造器的使用。 最后一部分是关于复杂查询的介绍。这一部分介绍了如何使用原生查询、使用注解进行查询以及使用自定义实现进行查询等。复杂查询是spring-data-elasticsearch一个非常重要的特性,通过它可以实现更加灵活和高级的查询功能。 总体来说,spring-data-elasticsearch官方教程文档提供了丰富的实例和详细的说明,对于想要学习和使用spring-data-elasticsearch框架的开发者来说,是一份非常有价值的指南。读者可以通过该文档逐步了解spring-data-elasticsearch的相关概念和基本用法,并通过实例演示快速上手。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Allen-xs

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值