springBoot集成 elasticsearch 并附上一些理解与操作

**在pom文件中引入elasticsearch

org.springframework.boot spring-boot-starter-data-elasticsearch ** ![在这里插入图片描述]() 在配置文件中 appliaction.yml中加入 ![在这里插入图片描述]() ![在这里插入图片描述]()

代码 如下: 实体类:

实体类常用注解:
**

注解@Document源码

springboot与es版本对应信息_springboot与es版本对应信息


@Document注解作用在类上,标记实体类为文档对象,常用属性如下:

(1)indexName:对应索引库名称;

(2)type:对应在索引库中的类型;

(3)shards:分片数

(4)replicas:副本数;

注解@Field源码

springboot与es版本对应信息_Test_02


@Field注解使用

@Field作用在成员变量,标记为文档的字段,并制定映射属性;

(1)@Id:作用在成员变量,标记一个字段为id主键;一般id字段或是域不需要存储也不需要分词;

(2)type:字段的类型,取值是枚举,FieldType;

(3)index:是否索引,布尔值类型,默认是true;

(4)store:是否存储,布尔值类型,默认值是false;

(5)analyzer:分词器名称

【 @Field(type = FieldType.Keyword)和 @Field(type = FieldType.Text)区别】
在早期elasticsearch5.x之前的版本存储字符串只有string字段;但是在elasticsearch5.x之后的版本存储了Keyword和Text,都是存储字符串的。FieldType.Keyword存储字符串数据时,不会建立索引;而FieldType.Text在存储字符串数据的时候,会自动建立索引,也会占用部分空间资源。

【 @Field(store = true)】

其实不管我们将store值设置为true或false,elasticsearch都会将该字段存储到Field域中;但是他们的区别是什么?
(1)store = false时,默认设置;那么给字段只存储在"_source"的Field域中;
(2)store = true时,该字段的value会存储在一个跟_source平级的独立Field域中;同时也会存储在_source中,所以有两份拷贝。
那么我们在什么样的业务场景下使用store field功能?
(1)_source field在索引的mapping 中disable了。这种情况下,如果不将某个field定义成store=true,那些将无法在返回的查询结果中看到这个field。
(2)_source的内容非常大。这时候如果我们想要在返回的_source document中解释出某个field的值的话,开销会很大(当然你也可以定义source filtering将减少network overhead),比例某个document中保存的是一本书,所以document中可能有这些field: title, date, content。假如我们只是想查询书的title 跟date信息,而不需要解释整个_source(非常大),这个时候我们可以考虑将title, date这些field设置成store=true。
需要注意的是,看起来将field store可以减少查询的开销,但其实这样也会加大disk的访问频率。假如你将_source中的10个field都定义store,那么在你查询这些field的时候会将会有10次disk seek的操作。而返回_source只有一次disk seek的操作。所以这个也是我们在定义的时候需要blance的。

*【注意】(1)@Field(index=true)表示是否索引,如果是索引表示该字段(或者叫域)能能够搜索。
   *【注意】(2)@Field(analyzer="ik_max_word",searchAnalyzer="ik_max_word")表示是否分词,如果是分词就会按照分词的单词搜索,如果不是分词就按照整体搜索。
    *【注意】((3)@Field(store=true)是否存储,也就是页面上显示。**

springboot与es版本对应信息_字段_03

controller(这里只简单贴出一点 因为没涉及到操作ES)

springboot与es版本对应信息_Test_04

商品搜索管理Service实现类

*** 使用QueryBuilder**
 * termQuery("key", obj) 完全匹配
 * termsQuery("key", obj1, obj2..)   一次匹配多个值
 * matchQuery("key", Obj) 单个匹配, field不支持通配符, 前缀具高级特性
 * multiMatchQuery("text", "field1", "field2"..);  匹配多个字段, field有通配符忒行
 * matchAllQuery();         匹配所有文件



 *** 组合查询**
 * must(QueryBuilders) :   AND
 * mustNot(QueryBuilders): NOT
 * should:                  : OR
 */

 * 只查询一个id的
 * QueryBuilders.idsQuery(String...type).ids(Collection<String> ids)
 * ![在这里插入图片描述]()

package com.wenbronk.javaes;

import java.net.InetSocketAddress;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.Map.Entry;

import org.elasticsearch.action.ListenableActionFuture;
import org.elasticsearch.action.get.GetRequestBuilder;
import org.elasticsearch.action.get.GetResponse;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.action.search.SearchType;
import org.elasticsearch.client.transport.TransportClient;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.text.Text;
import org.elasticsearch.common.transport.InetSocketTransportAddress;
import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.index.query.IndicesQueryBuilder;
import org.elasticsearch.index.query.NestedQueryBuilder;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.query.QueryStringQueryBuilder;
import org.elasticsearch.index.query.RangeQueryBuilder;
import org.elasticsearch.index.query.SpanFirstQueryBuilder;
import org.elasticsearch.index.query.WildcardQueryBuilder;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.junit.Before;
import org.junit.Test;

/**

  • java操作查询api
  • @author 231

*/
public class JavaESQuery {

private TransportClient client;

@Before
public void testBefore() {
    Settings settings = Settings.settingsBuilder().put("cluster.name", "wenbronk_escluster").build();
    client = TransportClient.builder().settings(settings).build()
             .addTransportAddress(new InetSocketTransportAddress(new InetSocketAddress("192.168.50.37", 9300)));
    System.out.println("success to connect escluster");
}

/**
 * 使用get查询
 */
@Test
public void testGet() {
    GetRequestBuilder requestBuilder = client.prepareGet("twitter", "tweet", "1");
    GetResponse response = requestBuilder.execute().actionGet();
    GetResponse getResponse = requestBuilder.get();
    ListenableActionFuture<GetResponse> execute = requestBuilder.execute();
    System.out.println(response.getSourceAsString());
}

/**
 * 使用QueryBuilder
 * termQuery("key", obj) 完全匹配
 * termsQuery("key", obj1, obj2..)   一次匹配多个值
 * matchQuery("key", Obj) 单个匹配, field不支持通配符, 前缀具高级特性
 * multiMatchQuery("text", "field1", "field2"..);  匹配多个字段, field有通配符忒行
 * matchAllQuery();         匹配所有文件
 */
@Test
public void testQueryBuilder() {

// QueryBuilder queryBuilder = QueryBuilders.termQuery(“user”, “kimchy”);
      QueryBUilder queryBuilder = QueryBuilders.termQuery(“user”, “kimchy”, “wenbronk”, “vini”);
QueryBuilders.termsQuery(“user”, new ArrayList().add(“kimchy”));
// QueryBuilder queryBuilder = QueryBuilders.matchQuery(“user”, “kimchy”);
// QueryBuilder queryBuilder = QueryBuilders.multiMatchQuery(“kimchy”, “user”, “message”, “gender”);
QueryBuilder queryBuilder = QueryBuilders.matchAllQuery();
searchFunction(queryBuilder);

}

/**
 * 组合查询
 * must(QueryBuilders) :   AND
 * mustNot(QueryBuilders): NOT
 * should:                  : OR
 */
@Test
public void testQueryBuilder2() {
    QueryBuilder queryBuilder = QueryBuilders.boolQuery()
        .must(QueryBuilders.termQuery("user", "kimchy"))
        .mustNot(QueryBuilders.termQuery("message", "nihao"))
        .should(QueryBuilders.termQuery("gender", "male"));
    searchFunction(queryBuilder);
}

/**
 * 只查询一个id的
 * QueryBuilders.idsQuery(String...type).ids(Collection<String> ids)
 */
@Test
public void testIdsQuery() {
    QueryBuilder queryBuilder = QueryBuilders.idsQuery().ids("1");
    searchFunction(queryBuilder);
}

/**
 * 包裹查询, 高于设定分数, 不计算相关性
 */
@Test
public void testConstantScoreQuery() {
    QueryBuilder queryBuilder = QueryBuilders.constantScoreQuery(QueryBuilders.termQuery("name", "kimchy")).boost(2.0f);
    searchFunction(queryBuilder);
    // 过滤查询

// QueryBuilders.constantScoreQuery(FilterBuilders.termQuery(“name”, “kimchy”)).boost(2.0f);

}

/**
 * disMax查询
 * 对子查询的结果做union, score沿用子查询score的最大值, 
 * 广泛用于muti-field查询
 */
@Test
public void testDisMaxQuery() {
    QueryBuilder queryBuilder = QueryBuilders.disMaxQuery()
        .add(QueryBuilders.termQuery("user", "kimch"))  // 查询条件
        .add(QueryBuilders.termQuery("message", "hello"))
        .boost(1.3f)
        .tieBreaker(0.7f);
    searchFunction(queryBuilder);
}

/**
 * 模糊查询
 * 不能用通配符, 不知道干啥用
 */
@Test
public void testFuzzyQuery() {
    QueryBuilder queryBuilder = QueryBuilders.fuzzyQuery("user", "kimch");
    searchFunction(queryBuilder);
}

/**
 * 父或子的文档查询
 */
@Test
public void testChildQuery() {
    QueryBuilder queryBuilder = QueryBuilders.hasChildQuery("sonDoc", QueryBuilders.termQuery("name", "vini"));
    searchFunction(queryBuilder);
}

/**
 * moreLikeThisQuery: 实现基于内容推荐, 支持实现一句话相似文章查询
 * {   
    "more_like_this" : {   
    "fields" : ["title", "content"],   // 要匹配的字段, 不填默认_all
    "like_text" : "text like this one",   // 匹配的文本
    }   
}     

percent_terms_to_match:匹配项(term)的百分比,默认是0.3

min_term_freq:一篇文档中一个词语至少出现次数,小于这个值的词将被忽略,默认是2

max_query_terms:一条查询语句中允许最多查询词语的个数,默认是25

stop_words:设置停止词,匹配时会忽略停止词

min_doc_freq:一个词语最少在多少篇文档中出现,小于这个值的词会将被忽略,默认是无限制

max_doc_freq:一个词语最多在多少篇文档中出现,大于这个值的词会将被忽略,默认是无限制

min_word_len:最小的词语长度,默认是0

max_word_len:最多的词语长度,默认无限制

boost_terms:设置词语权重,默认是1

boost:设置查询权重,默认是1

analyzer:设置使用的分词器,默认是使用该字段指定的分词器
 */
@Test
public void testMoreLikeThisQuery() {
    QueryBuilder queryBuilder = QueryBuilders.moreLikeThisQuery("user")
                        .like("kimchy");

// .minTermFreq(1) //最少出现的次数
// .maxQueryTerms(12); // 最多允许查询的词语
searchFunction(queryBuilder);
}

/**
 * 前缀查询
 */
@Test
public void testPrefixQuery() {
    QueryBuilder queryBuilder = QueryBuilders.matchQuery("user", "kimchy");
    searchFunction(queryBuilder);
}

/**
 * 查询解析查询字符串
 */
@Test
public void testQueryString() {
    QueryBuilder queryBuilder = QueryBuilders.queryStringQuery("+kimchy");
    searchFunction(queryBuilder);
}

/**
 * 范围内查询
 */
public void testRangeQuery() {
    QueryBuilder queryBuilder = QueryBuilders.rangeQuery("user")
        .from("kimchy")
        .to("wenbronk")
        .includeLower(true)     // 包含上界
        .includeUpper(true);      // 包含下届
    searchFunction(queryBuilder);
}

/**
 * 跨度查询
 */
@Test
public void testSpanQueries() {
     QueryBuilder queryBuilder1 = QueryBuilders.spanFirstQuery(QueryBuilders.spanTermQuery("name", "葫芦580娃"), 30000);     // Max查询范围的结束位置  
  
     QueryBuilder queryBuilder2 = QueryBuilders.spanNearQuery()  
            .clause(QueryBuilders.spanTermQuery("name", "葫芦580娃")) // Span Term Queries  
            .clause(QueryBuilders.spanTermQuery("name", "葫芦3812娃"))  
            .clause(QueryBuilders.spanTermQuery("name", "葫芦7139娃"))  
            .slop(30000)                                               // Slop factor  
            .inOrder(false)  
            .collectPayloads(false);  

    // Span Not
     QueryBuilder queryBuilder3 = QueryBuilders.spanNotQuery()  
            .include(QueryBuilders.spanTermQuery("name", "葫芦580娃"))  
            .exclude(QueryBuilders.spanTermQuery("home", "山西省太原市2552街道"));  

    // Span Or   
     QueryBuilder queryBuilder4 = QueryBuilders.spanOrQuery()  
            .clause(QueryBuilders.spanTermQuery("name", "葫芦580娃"))  
            .clause(QueryBuilders.spanTermQuery("name", "葫芦3812娃"))  
            .clause(QueryBuilders.spanTermQuery("name", "葫芦7139娃"));  

    // Span Term  
     QueryBuilder queryBuilder5 = QueryBuilders.spanTermQuery("name", "葫芦580娃");  
}

/**
 * 测试子查询
 */
@Test
public void testTopChildrenQuery() {
    QueryBuilders.hasChildQuery("tweet", 
            QueryBuilders.termQuery("user", "kimchy"))
        .scoreMode("max");
}

/**
 * 通配符查询, 支持 * 
 * 匹配任何字符序列, 包括空
 * 避免* 开始, 会检索大量内容造成效率缓慢
 */
@Test
public void testWildCardQuery() {
    QueryBuilder queryBuilder = QueryBuilders.wildcardQuery("user", "ki*hy");
    searchFunction(queryBuilder);
}

/**
 * 嵌套查询, 内嵌文档查询
 */
@Test
public void testNestedQuery() {
    QueryBuilder queryBuilder = QueryBuilders.nestedQuery("location", 
            QueryBuilders.boolQuery()
                .must(QueryBuilders.matchQuery("location.lat", 0.962590433140581))
                .must(QueryBuilders.rangeQuery("location.lon").lt(36.0000).gt(0.000)))
    .scoreMode("total");
    
}

/**
 * 测试索引查询
 */
@Test
public void testIndicesQueryBuilder () {
    QueryBuilder queryBuilder = QueryBuilders.indicesQuery(
            QueryBuilders.termQuery("user", "kimchy"), "index1", "index2")
            .noMatchQuery(QueryBuilders.termQuery("user", "kimchy"));
    
}



/**
 * 查询遍历抽取
 * @param queryBuilder
 */
private void searchFunction(QueryBuilder queryBuilder) {
    SearchResponse response = client.prepareSearch("twitter")
            .setSearchType(SearchType.DFS_QUERY_THEN_FETCH)
            .setScroll(new TimeValue(60000))
            .setQuery(queryBuilder)
            .setSize(100).execute().actionGet();
    
    while(true) {
        response = client.prepareSearchScroll(response.getScrollId())
            .setScroll(new TimeValue(60000)).execute().actionGet();
        for (SearchHit hit : response.getHits()) {
            Iterator<Entry<String, Object>> iterator = hit.getSource().entrySet().iterator();
            while(iterator.hasNext()) {
                Entry<String, Object> next = iterator.next();
                System.out.println(next.getKey() + ": " + next.getValue());
                if(response.getHits().hits().length == 0) {
                    break;
                }
            }
        }
        break;
    }

// testResponse(response);
}

/**
 * 对response结果的分析
 * @param response
 */
public void testResponse(SearchResponse response) {
    // 命中的记录数
    long totalHits = response.getHits().totalHits();
    
    for (SearchHit searchHit : response.getHits()) {
        // 打分
        float score = searchHit.getScore();
        // 文章id
        int id = Integer.parseInt(searchHit.getSource().get("id").toString());
        // title
        String title = searchHit.getSource().get("title").toString();
        // 内容
        String content = searchHit.getSource().get("content").toString();
        // 文章更新时间
        long updatetime = Long.parseLong(searchHit.getSource().get("updatetime").toString());
    }
}

/**
 * 对结果设置高亮显示
 */
public void testHighLighted() {
    /*  5.0 版本后的高亮设置
     * client.#().#().highlighter(hBuilder).execute().actionGet();
    HighlightBuilder hBuilder = new HighlightBuilder();
    hBuilder.preTags("<h2>");
    hBuilder.postTags("</h2>");
    hBuilder.field("user");        // 设置高亮显示的字段
    */
    // 加入查询中
    SearchResponse response = client.prepareSearch("blog")
        .setQuery(QueryBuilders.matchAllQuery())
        .addHighlightedField("user")        // 添加高亮的字段
        .setHighlighterPreTags("<h1>")
        .setHighlighterPostTags("</h1>")
        .execute().actionGet();
    
    // 遍历结果, 获取高亮片段
    SearchHits searchHits = response.getHits();
    for(SearchHit hit:searchHits){
        System.out.println("String方式打印文档搜索内容:");
        System.out.println(hit.getSourceAsString());
        System.out.println("Map方式打印高亮内容");
        System.out.println(hit.getHighlightFields());

        System.out.println("遍历高亮集合,打印高亮片段:");
        Text[] text = hit.getHighlightFields().get("title").getFragments();
        for (Text str : text) {
            System.out.println(str.string());
        }
    }
}

}

springboot与es版本对应信息_Test_05


springboot与es版本对应信息_字段_06


springboot与es版本对应信息_Test_07


springboot与es版本对应信息_Test_08

springboot与es版本对应信息_字段_09


springboot与es版本对应信息_springboot与es版本对应信息_10


springboot与es版本对应信息_字段_11

DAO

springboot与es版本对应信息_springboot与es版本对应信息_12

ElasticsearchRepository源码 提供了简单的增伤改查

springboot与es版本对应信息_springboot与es版本对应信息_13