【ElasticSearch】es简单使用

es可以做到多字段模糊搜索,因其易用,被广大研发人员使用,最近小编就接到模糊搜索的需求,之前用过solr,通过看搜索引擎使用热度和排名,es近几年明显上升,小编公司所用也是es,那便来看看我们如何使用吧,本篇只做简单介绍es的使用方法,以及效果,关于原理小编日后补充。

es现在已有6.x版本,我们项目用的是5.5.3版本,更低版本的使用方式和高版本不太一样,这个大家注意下,可能影响到后来的使用。

一、es引入jar:

<!-- elasticsearch -->
<dependency>
    <groupId>io.searchbox</groupId>
    <artifactId>jest</artifactId>
    <version>5.3.4</version>
</dependency>
<dependency>
    <groupId>org.elasticsearch</groupId>
    <artifactId>elasticsearch</artifactId>
    <version>5.6.13</version>
</dependency>

二、配置连接:

@Configuration
public class JestConfig {
    @Value("${userName}")
    private String userName;
    @Value("${password}")
    private String password;
    @Value("${serverUri}")
    private String serverUri;

    private static String staticUrl;
    private static String staticUserName;
    private static String staticPassword;

    @PostConstruct
    private void init() {
        JestConfig.staticUrl = serverUri;
        JestConfig.staticUserName = userName;
        JestConfig.staticPassword = password;
    }

    public static void getJestClient() throws Exception{
        JestClientFactory factory = new JestClientFactory();
        factory.setHttpClientConfig(new HttpClientConfig
                .Builder("***")
                .defaultCredentials("**", "**")
                .gson(new GsonBuilder().setDateFormat("yyyy-MM-dd HH:mm:ss").create())
                .connTimeout(5000)
                .readTimeout(5000)
                .multiThreaded(true)
                .build());

        JestClient jest= factory.getObject();
		//删除索引
        JestResult jr = jest.execute(new DeleteIndex.Builder("indexname").build());
        System.out.println(jr.isSucceeded());
    }

    public static void main(String[] args) {
        try {
            getJestClient();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Bean
    public JestClient getClient() {
        JestClient client = null;
        try {
            JestClientFactory factory = new JestClientFactory();
            factory.setHttpClientConfig(new HttpClientConfig
                    .Builder(serverUri)
                    .defaultCredentials(userName, password)
                    .gson(new GsonBuilder().setDateFormat("yyyy-MM-dd HH:mm:ss").create())
                    .connTimeout(3000)
                    .readTimeout(3000)
                    .multiThreaded(true)
                    .build());
            client = factory.getObject();
        } catch (Exception e) {
            log.error("JestClient connection Exception :",e);
        }
        return client;
    }
}

三、Jest管理es,写通用类:

@Autowired
    private JestClient jestClient;
    private String indexName = "indexname";

    @Override
    public void save(String typeName, String id, Object obj, String mappingStr) throws Exception {
        createIndex();
        if (!StringUtils.isEmpty(mappingStr)) {
            if (!existMapping(typeName)) {
                createIndexMapping(typeName, mappingStr);
            }
        }
        Index index = new Index.Builder(obj).index(indexName).type(typeName).id(id).build();
        JestResult result = jestClient.execute(index);
        if (!result.isSucceeded()) {
            throw new Exception(result.getErrorMessage());
        }

    }

    @Override
    public void updateById(String typeName, String id, Object obj) throws Exception {
//        StringBuilder script =new StringBuilder();
//        script.append("{").append( "\"doc\":").append(JSONObject.fromObject(obj)).append( "}");
//        Update update = new Update.Builder(script).index(indexName).type(indexName).id(id).build();
//        JestResult result = jestClient.execute(update);
        Index index = new Index.Builder(obj).index(indexName).type(typeName).id(id).build();
        JestResult result = jestClient.execute(index);
        if (!result.isSucceeded()) {
            throw new Exception(result.getErrorMessage());
        }
        if (!result.isSucceeded()) {
            throw new Exception(result.getErrorMessage());
        }

    }

    @Override
    public void deleteById(String typeName, String id) throws Exception {
        DocumentResult dr = jestClient.execute(new Delete.Builder(id).index(indexName).type(typeName).build());
        if (!dr.isSucceeded() && dr.getResponseCode() != 404) {
            throw new Exception(dr.getErrorMessage());
        }

    }

    @Override
    public QueryPageResEntity queryPage(String typeName, QueryPageReqEntity req) throws Exception {
        QueryPageResEntity response = new QueryPageResEntity();
        List list = new ArrayList();
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();

        if (req.getLimit() != null && req.getPage() != null) {
            searchSourceBuilder.size(req.getLimit());
            searchSourceBuilder.from((req.getPage() - 1) * req.getLimit());
        }
        List<QueryConditionEntity> matchQueryList = req.getMatchQueryList();
        List<QueryConditionEntity> termsQueryList = req.getTermsQueryList();
        List<QueryConditionEntity> wildcardQueryList = req.getWildcardQueryList();
        List<QueryConditionEntity> shouldQueryList = req.getShouldQueryList();
        List<QueryConditionEntity> sortList = req.getSortList();
        if (req.isAllflag()) {
            searchSourceBuilder.query(QueryBuilders.matchAllQuery());
        } else {
            matchQueryList.stream().forEach(m -> {
                //QueryBuilders.multiMatchQuery()
                QueryBuilder queryBuilder = QueryBuilders.matchQuery(m.getKey(), m.getValue());
                searchSourceBuilder.query(queryBuilder);
            });
            termsQueryList.stream().forEach(m -> {
                QueryBuilder queryBuilder = QueryBuilders.termQuery(m.getKey(), m.getValue());
                searchSourceBuilder.query(queryBuilder);
            });
            wildcardQueryList.stream().forEach(m -> {
                QueryBuilder queryBuilder = QueryBuilders.wildcardQuery(m.getKey(), "*" + m.getValue() + "*");
                searchSourceBuilder.query(queryBuilder);
            });
            if (!shouldQueryList.isEmpty()) {
                BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
                shouldQueryList.stream().forEach(m -> {
                    boolQueryBuilder.should(QueryBuilders.matchQuery(m.getKey(), m.getValue()));
                });
                searchSourceBuilder.query(boolQueryBuilder);
            }


        }
//        QueryBuilder queryBuilder = QueryBuilders
//                  .termsQuery("author", new String[]{ "1111", "2222" });//多值完全匹配查询
//        QueryBuilder queryBuilder = QueryBuilders
//               .wildcardQuery("title", "*:*");//通配符和正则表达式查询
//        字段名模糊值:如 *123* ;?123*;?123?;*123?
//        QueryBuilder queryBuilder = QueryBuilders
//            .prefixQuery("author", "11");//前缀查询
//        QueryBuilder queryBuilder = QueryBuilders
//                   .rangeQuery("date")
//                   .gte("2019-02-20T15:43:48")
//                   .lte("2019-02-20T15:55:45")
//                   .includeLower(true)
//                   .includeUpper(true);//区间查询
        //QueryBuilder queryBuilder = QueryBuilders
        //    .queryStringQuery(QueryParser.escape("T:o\""));//文本检索,应该是将查询的词先分成词库中存在的词,
//然后分别去检索,存在任一存在的词即返回,查询词分词后是OR的关系。需要转义特殊字符

        sortList.stream().forEach(m -> {
            searchSourceBuilder.sort(m.getKey(), (SortOrder) m.getValue());
        });
        String query = searchSourceBuilder.toString();
        Search search = new Search.Builder(query).addIndex(indexName).addType(typeName).build();
        SearchResult result = jestClient.execute(search);
        if (!result.isSucceeded()) {
            response.setList(list);
            response.setTotal(0);
            return response;
        }
        List<Hit<Object, Void>> hits = result.getHits(req.getCls());
        for (Hit<Object, Void> hit : hits) {
            list.add(hit.source);
        }
        response.setList(list);
        response.setTotal(result.getTotal().intValue());
        return response;

    }

    private JestResult selectAllIndex() throws IOException {
        Cat cat = new Cat.IndicesBuilder().build();
        return jestClient.execute(cat);
    }

    /**
     * 创建索引:如果索引不存在则创建,存在不处理
     */
    private void createIndex() throws Exception {
        boolean flag = existIndex();
        if (!flag) {
            JestResult result = jestClient.execute(new CreateIndex.Builder(indexName).build());
            if (!result.isSucceeded()) {
                throw new Exception(result.getErrorMessage());
            }
        }

    }

    /**
     * 检查索引是否存在true false 判断
     * false 不存在
     * true 存在
     * * @return
     */
    private boolean existIndex() throws Exception {
        IndicesExists indicesExists = new IndicesExists.Builder(indexName).build();
        JestResult jestResult = jestClient.execute(indicesExists);
        return jestResult.isSucceeded();
    }

    /**
     * 检查映射关系是否存在
     * false 不存在
     * ture 存在
     *
     * @param typeName
     * @return
     * @throws Exception
     */
    private boolean existMapping(String typeName) throws Exception {
        GetMapping.Builder builder = new GetMapping.Builder();
        builder.addIndex(indexName).addType(typeName);
        JestResult jr = jestClient.execute(builder.build());
        return jr.isSucceeded();
    }

    /***
     * 创建映射
     * @param typeName
     * @param mappingStr
     * @return
     * @throws Exception
     */
    private boolean createIndexMapping(String typeName, String mappingStr) throws Exception {
        PutMapping putMapping = new PutMapping.Builder(indexName, typeName, mappingStr).build();
        JestResult jr = jestClient.execute(putMapping);
        return jr.isSucceeded();
    }

    /**
     * 删除索引
     *
     * @param indexName
     * @return
     * @throws Exception
     */
    private boolean deleteIndex(String indexName) throws Exception {
        JestResult jr = jestClient.execute(new DeleteIndex.Builder(indexName).build());
        return jr.isSucceeded();
    }
    private boolean deleteIndexType(String type)throws Exception{
        JestResult jr = jestClient.execute(new DeleteIndex.Builder(indexName).type(type).build());
        return jr.isSucceeded();
    }

    private Object getById(String indexName, String id, Class cls) throws Exception {
        Get get = new Get.Builder(indexName, id).build();
        JestResult result = jestClient.execute(get);
        return result.getSourceAsObject(cls);
    }

四、写自己的业务实现类,做字段mapping映射,然后建立索引:

@Override
public void addSearchCarModel(CarModelEasyepcModel modelEasyepc) {
    try {
    	//建立映射后建立索引
        jestService.save(indexTypeName,modelEasyepc.getModelId(),modelEasyepc,getQueryMappingStr(indexTypeName));
    } catch (Exception e) {
        e.printStackTrace();
    }
}
/**
 *  建立映射
 */
private String getQueryMappingStr(String typeName) {
    StringBuilder source = new StringBuilder();
    source.append("{\"").append(typeName).append("\":{\"properties\":{")
            .append("\"modelId\":{\"type\":\"string\"}")
            .append(",\"yearPattern\":{\"type\":\"string\",\"index\":\"analyzed\",\"analyzer\":\"ik\",\"search_analyzer\": \"ik_smart\"}")
            .append(",\"brandName\":{\"type\":\"string\",\"index\":\"analyzed\",\"analyzer\":\"ik\",\"search_analyzer\": \"ik_smart\"}")
            .append(",\"brandId\":{\"type\":\"string\"}")
            .append(",\"brandCode\":{\"type\":\"string\"}")
            .append("}}}");
    return source.toString();
}

存入之后,查询逻辑如下:

QueryPageReqEntity entity = new QueryPageReqEntity();
        entity.setPage(1);
        entity.setLimit(20);//固定取20条,不分页
        try {
            if (!StringUtils.isEmpty(carModelEasyepcReqModel.getModelKey())){
                entity.setAllflag(false);
                List<QueryConditionEntity> shouldQueryList = entity.getShouldQueryList();
                QueryConditionEntity yearPattern = new QueryConditionEntity();
                yearPattern.setKey("yearPattern");
                yearPattern.setValue(carModelEasyepcReqModel.getModelKey());
                QueryConditionEntity brandName = new QueryConditionEntity();
                brandName.setKey("brandName");
                cfgLevel.setValue(carModelEasyepcReqModel.getModelKey());
                shouldQueryList.add(yearPattern);
                shouldQueryList.add(brandName);
            }
            entity.setCls(CarModelEasyepcModel.class);
            //entity set进去sortList  todo
            QueryPageResEntity res = null;
            res = jestService.queryPage(indexTypeName,entity);
            List list = res.getList();
            List<CarModelEasyepcModel> listVo = new ArrayList<>();
            list.stream().forEach(s -> {
                CarModelEasyepcModel v = CarModelEasyepcModel.builder().build();
                BeanUtils.copyProperties(s, v);
                listVo.add(v);
            });
            CarModelEasyepcRespModel modelEasyepcRespModel = CarModelEasyepcRespModel.builder().model(listVo).build();

五、索引建立确认是否分词:
了解映射的建立:大家可以参考以下文章,字段指代的意思很明确:
https://www.iteye.com/blog/m635674608-2259804

“index”:"analyzed"代表字段分词,not_analyzed代表不分词;
“analyzer”:"ik"代表存入es的时候使用ik分词器;
“search_analyzer”: "ik_smart"代表查询es时分词方式;

ik_max_word:会将文本做最细粒度的拆分,例如「中华人民共和国国歌」会被拆分为「中华人民共和国、中华人民、中华、华人、人民共和国、人民、人、民、共和国、共和、和、国国、国歌」,会穷尽各种可能的组合;
ik_smart:会将文本做最粗粒度的拆分,例如「中华人民共和国国歌」会被拆分为「中华人民共和国、国歌」;

需要注意的是大家如果建立过一次映射,以后如果有什么改动千万记得删除原来的重新建立映射,否则不起作用,亲身体会,请大家注意!

六、效果:
在这里插入图片描述
调接口,根据“2012基本”匹配,即根据年款和品牌名称匹配,查出相应的结果。

总结:
好东西值得研究,单学会使用,不研究原理,可能遇到的某些问题自己解释不了,接下来还是需要看下原理。

加油,先尝尝甜头,再深入研究点东西,岂不乐哉?!

发布了253 篇原创文章 · 获赞 76 · 访问量 29万+

猜你喜欢

转载自blog.csdn.net/hongwei15732623364/article/details/100043612