Springboot+ElasticSearch7.4.2实现全文搜索和猜你喜欢业务

我们公司之前有做过模仿电商类型项目,模仿电商对服务进行智能搜索,用户搜索内容进行记录,然后查询记录表的记录完成猜你喜欢的简单业务,然后之后我按照这个思路用了Elasticsearch新版7来实现这个业务。

准备情况:安装完Elasticsearch,最好安装kibana可视化,版本需和es一致。我的kibana设置的中文。

1.首先Springboot和Elasticsearch7进行集成,我的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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>df.es7</groupId>
    <artifactId>df-es7</artifactId>
    <version>1.0.0-SNAPSHOT</version>
    <packaging>jar</packaging>

    <name>df-es7</name>
    <description>df学习es7</description>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.0.4.RELEASE</version>
        <relativePath/>
    </parent>
    <dependencies>

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


        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.16.14</version>
            <scope>provided</scope>
        </dependency>

        <dependency>
            <groupId>org.elasticsearch</groupId>
            <artifactId>elasticsearch</artifactId>
            <version>7.4.2</version>
        </dependency>

        <dependency>
            <groupId>org.elasticsearch.client</groupId>
            <artifactId>elasticsearch-rest-high-level-client</artifactId>
            <version>7.4.2</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jdbc</artifactId>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.38</version>
        </dependency>
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
            <version>3.4</version>
        </dependency>
        <!-- fastjson -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.54</version>
        </dependency>

    </dependencies>
    <repositories><!-- 代码库 -->
        <repository>
            <id>maven-ali</id>
            <url>http://maven.aliyun.com/nexus/content/groups/public//</url>
            <releases>
                <enabled>true</enabled>
            </releases>
            <snapshots>
                <enabled>true</enabled>
                <updatePolicy>always</updatePolicy>
                <checksumPolicy>fail</checksumPolicy>
            </snapshots>
        </repository>
    </repositories>
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>


</project>

2.然后创建工具类用来连接es

package df.es7.util;

import org.apache.http.HttpHost;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestClientBuilder;
import org.elasticsearch.client.RestHighLevelClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import java.io.IOException;

/**
 * @Author df
 * @Date 2020/1/16 15:20
 * @Version 1.0
 */
@Component
public class ElasticServiceUtils {
    private final static Logger logger = LoggerFactory.getLogger(ElasticServiceUtils.class);
    private static RestHighLevelClient restHighLevelClient;

    /**
     * <li>Description: 在Servlet容器初始化前执行 </li>
     */
    @PostConstruct
    public static RestHighLevelClient init() {
        try {
            if (restHighLevelClient != null) {
                restHighLevelClient.close();
            }
            //节点1和2
            HttpHost node1 = new HttpHost("你的ip地址", 9200, "http");
            RestClientBuilder builder = RestClient.builder(node1);
            restHighLevelClient = new RestHighLevelClient(builder);
        } catch (IOException e) {
            e.printStackTrace();
            logger.error(e.getMessage());
        }
        return restHighLevelClient;
    }
}

3.在kibana创建用户搜索表,为注册资源表(之后创建索引和字段我会在代码实现,别着急)

put registered_kj_resource
{
  "mappings": { 
      "properties": { 
        "DCID":    { "type": "integer"  }, 
        "DCGROUP_ID":     { "type": "integer"  }, 
        "DCNAME":      { "type": "text" },  
        "DCCODE":      { "type": "text" },  
        "DCADDRESS":      { "type": "text" }, 
        "DATA_RESOURCE":      { "type": "text" }, 
        "DCAREA":      { "type": "text" }, 
         "DESCRIPTION":      { "type": "text" }, 
         "DCSECURITY_LEVEL":      { "type": "text" }, 
         "RESOURCE_SUMMARY":      { "type": "text" }, 
        "CREATE_TIME":  {
          "type":   "date", 
          "format": "strict_date_optional_time||epoch_millis"
        }
      }
    },
  "settings":{
    "index":{
    "number_of_shards": 1,
    "number_of_replicas": 1
    }
  }
}

 4.我在kibana创建的索引,在kibana索引管理里边能查看到索引信息,这个registered_kj_resource索引就是让用户进行搜索的数据。

5.然后往这个注册资源表里插入数据,我是mysql库里有数据,我就直接查库然后往es插入数据

 public List<Map<String, Object>> select() {
        return jdbcTemplate.queryForList("select * from registered_kj_resource");
 }
//这里index传输的是registered_kj_resource
public void insertData(String index) {
        IndexRequest indexRequest = new IndexRequest(index);
        //获取库的信息
        List<Map<String, Object>> datas = select();
        for (Map map : datas) {
            // mysql库是yyyy-mm-dd hh:ss:mm日期,es我设置的是yyyy-mm-dd所以这里我做了判断,否则不能插入
            if (map.containsKey("CREATE_TIME") &&
                    map.get("CREATE_TIME") != null) {
                String time = timeToString((Timestamp) map.get("CREATE_TIME"));
                map.put("CREATE_TIME", time.substring(0, 10));
            }
            if (map.containsKey("DATA_TIME") &&
                    map.get("DATA_TIME") != null) {
                map.put("DATA_TIME", timeToString((Timestamp) map.get("DATA_TIME")));
            }
            indexRequest.source(map, XContentType.JSON);
            try {
                IndexResponse indexResponse = ElasticServiceUtils.init().index(indexRequest, RequestOptions.DEFAULT);
                if (indexResponse != null) {
                    String id = indexResponse.getId();
                    String index1 = indexResponse.getIndex();
                    long version = indexResponse.getVersion();
                    log.info("index:{},id:{}", index1, id);
                    if (indexResponse.getResult() == DocWriteResponse.Result.CREATED) {
                        System.out.println("新增文档成功!" + index1 + "-" + id + "-" + version);
                        // return new ResponseBean(200, "插入成功", id);
                    } else if (indexResponse.getResult() == DocWriteResponse.Result.UPDATED) {
                        System.out.println("修改文档成功!");
                        // return new ResponseBean(10001, "插入失败", null);
                    }
                    // 分片处理信息
                    ReplicationResponse.ShardInfo shardInfo = indexResponse.getShardInfo();
                    if (shardInfo.getTotal() != shardInfo.getSuccessful()) {
                        System.out.println("分片处理信息.....");
                    }
                    // 如果有分片副本失败,可以获得失败原因信息
                    if (shardInfo.getFailed() > 0) {
                        for (ReplicationResponse.ShardInfo.Failure failure : shardInfo.getFailures()) {
                            String reason = failure.reason();
                            System.out.println("副本失败原因:" + reason);
                        }
                    }

                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

6.咱们用kibana查询一下,看看里边是否有数据?有269条数据

7.我们现在开始用代码来进行匹配查询,匹配查询出来的数据要录入到数据搜索记录表里边,所以我们要新建一个索引和文档名叫search_data_record。

 
//这里index传search_data_record
public void createIndex(String index) {
        try {
            XContentBuilder builder = XContentFactory.jsonBuilder()
                    .startObject()
                    .field("properties")
                    .startObject()
                    // dcid是registered_kj_resource的DCID,两个表关联
                    .field("dcid").startObject().field("index", "true").field("type", "integer").endObject()
                    // 操作的用户
                    .field("userid").startObject().field("index", "true").field("type", "integer").endObject()
                    // dcName是registered_kj_resource的DCNAME
                    .field("dcName").startObject().field("index", "true").field("type", "text").endObject()
                   // keyName记录搜索的关键字
                    .field("keyName").startObject().field("index", "true").field("type", "text").endObject()
                   // summery摘要,在registered_kj_resource表中其实这个在做猜你喜欢是很重要的,相当于类别
                    .field("summery").startObject().field("index", "true").field("type", "text").endObject()
                    .field("createTime").startObject().field("index", "true").field("type", "date").field("format", "yyyy-MM-dd HH:mm:ss").endObject()
                    .endObject().endObject();
            CreateIndexRequest request = new CreateIndexRequest(index);
            request.mapping(index, builder);
            CreateIndexResponse createIndexResponse = ElasticServiceUtils.init().indices().create(request, RequestOptions.DEFAULT);
            boolean acknowledged = createIndexResponse.isAcknowledged();
            if (acknowledged) {
                log.info("创建成功");
            } else {
                log.info("创建失败");
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

8.创建成功了!

9. 开始模拟用户搜索查询了,根据关键词搜索的时候,也会把搜索数据记录到记录表里,用做猜你喜欢业务

// 这里index传registered_kj_resource
public JSONArray query(String index, String dcName, String userId) {
        SearchRequest searchRequest = new SearchRequest(index);
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        // 默认设置13条数据
        sourceBuilder.size(13);
        // 按匹配查询
        sourceBuilder.query(QueryBuilders.matchQuery("DCNAME", dcName));
        sourceBuilder.timeout(new TimeValue(60, TimeUnit.SECONDS));
        searchRequest.source(sourceBuilder);
        JSONArray jsonArray = new JSONArray();
        try {
            SearchResponse response = ElasticServiceUtils.init().search(searchRequest, RequestOptions.DEFAULT);
            SearchHits hits = response.getHits();
            //int length = hits.getHits().length;
            for (SearchHit hit : hits) {
                String sourceAsString = hit.getSourceAsString();
                JSONObject jsonObject = JSON.parseObject(sourceAsString);
                jsonArray.add(jsonObject);
                // 查询记录表
                JSONObject dataRecode = queryTerm("search_data_record", jsonObject.get("DCID").toString());
                Boolean isInsertRecode = false;
                if (dataRecode != null && dataRecode.size() > 0) {
                    // id不相等或不是同一用户时插入数据
                    if ((Integer.parseInt(dataRecode.get("dcid").toString()) !=
                            Integer.parseInt(jsonObject.get("DCID").toString())) ||
                            !dataRecode.get("userid").toString().equals(userId)) {
                        isInsertRecode = true;
                    }
                } else {
                    // 将搜索的记录存储到记录表里
                    isInsertRecode = true;
                }
                if (isInsertRecode) {
                    JSONObject searchObject = new JSONObject();
                    searchObject.put("dcName", jsonObject.get("DCNAME") != null ? jsonObject.get("DCNAME") : "");
                    searchObject.put("dcid", jsonObject.get("DCID") != null ? jsonObject.get("DCID") : "");
                    searchObject.put("keyName", dcName);
                    searchObject.put("summery", jsonObject.get("RESOURCE_SUMMARY") != null ? jsonObject.get("RESOURCE_SUMMARY") : "");
                    searchObject.put("userid", userId);
                    searchObject.put("createTime", getNowTime());
                    insertSearchData("search_data_record", searchObject);
                }
            }
            log.info("查询成功:{}", jsonArray);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return jsonArray;
    }
    public static String getNowTime() {
        LocalDate today = LocalDate.now();
        StringBuffer nowTime = new StringBuffer(today.toString());
        LocalDateTime dt = LocalDateTime.now();
        // 时
        if (dt.getHour() < 10) {
            nowTime.append(" 0" + dt.getHour() + ":");
        } else {
            nowTime.append(" " + dt.getHour() + ":");
        }
        // 分
        if (dt.getMinute() < 10) {
            nowTime.append("0" + dt.getMinute() + ":");
        } else {
            nowTime.append(dt.getMinute() + ":");
        }
        // 秒
        if (dt.getSecond() < 10) {
            nowTime.append("0" + dt.getSecond());
        } else {
            nowTime.append(dt.getSecond());
        }
        //System.out.println(nowTime);
        return nowTime.toString();
    }

 

 10.记录表插入数据

 public void insertSearchData(String index, JSONObject object) {
        IndexRequest indexRequest = new IndexRequest(index);
        indexRequest.source(object, XContentType.JSON);
        try {
            IndexResponse indexResponse = ElasticServiceUtils.init().index(indexRequest, RequestOptions.DEFAULT);
            if (indexResponse != null) {
                if (indexResponse.getResult() == DocWriteResponse.Result.CREATED) {
                    System.out.println("新增数据成功!" + object);
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

11.精确查询记录表关联id,目的,如果存在就不插入,不存在就插入

public JSONObject queryTerm(String index, String id) {
        SearchRequest searchRequest = new SearchRequest(index);
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        // 默认设置13条数据
        sourceBuilder.size(13);
        sourceBuilder.query(QueryBuilders.termQuery("dcid", id));
        searchRequest.source(sourceBuilder);
        //JSONArray jsonArray = new JSONArray();
        JSONObject jsonObject = new JSONObject();
        try {
            SearchResponse response = ElasticServiceUtils.init().search(searchRequest, RequestOptions.DEFAULT);
            SearchHits hits = response.getHits();
            for (SearchHit hit : hits) {
                String sourceAsString = hit.getSourceAsString();
                jsonObject = JSON.parseObject(sourceAsString);
                // jsonArray.add(jsonObject);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return jsonObject;
    }

 

12.启动项目,查询一下!

 12.然后猜你喜欢接口的实现!其实就是查询记录!

// 这里index是search_data_record表
public JSONArray guessLike(String index, String userId) {
        SearchRequest searchRequest = new SearchRequest(index);
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        // 默认设置13条数据
        sourceBuilder.size(13);
        // 精确查询,根据时间降序
        sourceBuilder.query(QueryBuilders.termQuery("userid", userId)).sort("createTime", SortOrder.DESC);     
        searchRequest.source(sourceBuilder);
        JSONArray jsonArray = new JSONArray();
        try {
            SearchResponse response = ElasticServiceUtils.init().search(searchRequest, RequestOptions.DEFAULT);
            SearchHits hits = response.getHits();
            for (SearchHit hit : hits) {
                String sourceAsString = hit.getSourceAsString();
                JSONObject jsonObject = JSON.parseObject(sourceAsString);
                jsonArray.add(jsonObject);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return jsonArray;
    }

13.因为之前也有搜索过人口,默认我能查13条,所以这里又包含交通,也包含人口!

 到这里就介绍这些,希望对你有帮助!

1.其实还有细节需要更改,在用户搜索的那张表其实可以根据名称,当查询名称最终结果不足13条的时候,可以根据资源摘要也就是类别继续探索查询!直到够13条就可

 

3.目前es7比较新,资料比较少,这样写不是最优模式,查询较慢,我们可以一起探索好的方式。

4.那么以上的问题,我有机会在逐个解决的!

  • 2
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 9
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值