Spring boot + Elasticsearch

目的

为了在spring boot 项目中使用elasticsearch进行增删改查,个人感觉elasticsearch 查询是最重要的部分;

1.采用ElasticsearchRepository进行对象的插入,查询,修改,删除
2.采用QueryBuilders 构建查询dsl(domain specific language);

javaBean es CURD

javaBean 通过ElasticsearchRepository 持久化到elasticsearch 内存, 然后支持查询,修改,删除
@Document(indexName = "company", type = "_doc", shards = 1, replicas = 0, refreshInterval = "-1")
public class Employee implements Serializable {
    @Id
    private String id;
    @Field
    private String firstName;
    @Field
    private String lastName;
    @Field
    private Integer age = 0;
    @Field
    private String address;

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getFirstName() {
        return firstName;
    }

    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }

    public String getLastName() {
        return lastName;
    }

    public void setLastName(String lastName) {
        this.lastName = lastName;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }
}

@Repository
public interface EmployeeRepository extends ElasticsearchRepository<Employee, String> {

    /**
     * @author shenzm
     * @param id
     * @return
     */
    public Employee queryEmployeeById(String id);
}


/**
 * @author shenzm
 * @date 2019-2-28
 * @description 作用
 */

@RestController
@RequestMapping(value = "/es")
public class EmployeeController {

    private static final Logger logger = LoggerFactory.getLogger(EmployeeController.class);

    @Autowired
    private EmployeeRepository employeeRepository;

    /**
     * 添加
     *
     * @return
     */
    @RequestMapping("/removeAll")
    public String remove() {
        employeeRepository.deleteAll();
        return "success";
    }

    /**
     * 添加
     *
     * @return
     */
    @RequestMapping("/add")
    public String add(@RequestParam("firstName") String firstName, @RequestParam("lastName") String lastName) {
        Employee employee = new Employee();
        employee.setId(UUID.randomUUID().toString());
        employee.setFirstName(firstName);
        employee.setLastName(lastName);
        employee.setAge(26);
        employee.setAddress("上海 浦东新区");
        employeeRepository.save(employee);
        return "success";
    }

    /**
     * 删除
     *
     * @return
     */
    @RequestMapping("/delete")
    public String delete() {
        Employee employee = employeeRepository.queryEmployeeById("1");
        employeeRepository.delete(employee);
        return "success";
    }

    /**
     * 局部更新
     *
     * @return
     */
    @RequestMapping("/update")
    public String update() {
        Employee employee = employeeRepository.queryEmployeeById("1");
        employee.setFirstName("哈哈");
        employeeRepository.save(employee);
        return "success";
    }

    /**
     * 查询
     *
     * @return
     */
    @RequestMapping("/query")
    public Employee query(@RequestParam("id") String id) {
        Employee employee = employeeRepository.queryEmployeeById(id);
        String json = JSONObject.toJSONString(employee);
        logger.info(json);
        return employee;
    }

}

QueryBuilder的简单使用

 直接上代码 : QueryBuilder 可将dsl 转为java 语言的查询

/**
 * @author shenzm
 * @date 2019-2-28
 * @description 作用
 *
 * 参考:https://blog.csdn.net/kingice1014/article/details/72899776
 */

@RestController
@RequestMapping(value = "/es/person")
public class PersonController {

    private static final Logger logger = LoggerFactory.getLogger(EmployeeController.class);

    @Autowired
    private PersonRepository personRepository;

    @RequestMapping("/init")
    public void initData() throws IOException {
        InputStream in = this.getClass().getClassLoader().getResourceAsStream("a.json");
        BufferedInputStream bis = new BufferedInputStream(in);
        byte[] bytes = new byte[1024];
        int len = 0;
        StringBuffer buffer = new StringBuffer();
        while ((len = bis.read(bytes)) != -1) {
            buffer.append(new String(bytes, 0, len));
        }
        String json = buffer.toString();
        logger.info(json);

        JSONObject jsonObject = JSONObject.parseObject(json);
        Object hits = jsonObject.get("hits");
        JSONArray jarr = JSONArray.parseArray(hits.toString());
        for (int i = 0; i < jarr.size(); i++) {
            JSONObject dataJson = JSONObject.parseObject(jarr.get(i).toString());
            String _id = dataJson.get("_id").toString();
            String _source = dataJson.get("_source").toString();
            JSONObject sourceObj = JSONObject.parseObject(_source);
            int account_number = Integer.valueOf(sourceObj.get("account_number").toString());
            long balance = Long.valueOf(sourceObj.get("balance").toString());
            String firstname = sourceObj.get("firstname").toString();
            String lastname = sourceObj.get("lastname").toString();
            int age = Integer.valueOf(sourceObj.get("age").toString());
            String gender = sourceObj.get("gender").toString();
            String address = sourceObj.get("address").toString();
            String employer = sourceObj.get("employer").toString();
            String email = sourceObj.get("email").toString();
            String city = sourceObj.get("city").toString();
            String state = sourceObj.get("state").toString();
            Person person = new Person(Long.valueOf(_id), account_number, balance, firstname, lastname, age, gender, address, employer, email, city, state);
            personRepository.save(person);
        }
    }

    @RequestMapping("/matchQuery")
    public List<Person> matchQuery() throws IOException {
        //id 排序; firstname 符合 Blake 的所有的记录
        PageRequest pageRequest = PageRequest.of(0, 50);
        FieldSortBuilder idSortBuilder = SortBuilders.fieldSort("id").order(SortOrder.ASC);
        MatchQueryBuilder matchQueryBuilder = QueryBuilders.matchQuery("age", 30);
        NativeSearchQuery nativeSearchQuery = new NativeSearchQueryBuilder().withQuery(matchQueryBuilder)
                .withPageable(pageRequest)
                .withSort(idSortBuilder)
                .build();
        String query = nativeSearchQuery.getQuery().toString();
        logger.info(query);
        List<Person> content = personRepository.search(nativeSearchQuery).getContent();
        return content;
    }

    /**
     * terms 测试  term 的value 如果为中文ok没问题, 如果是英文  首字母大写  需要通过小写的单词 去匹配
     *
     * 例如 写成这样 QueryBuilders.termsQuery("firstname", "Vera", "Kari", "Blake");是匹配不到记录的
     *
     * 参考了:https://www.cnblogs.com/shaosks/p/7813729.html
     *
     *
     * @return
     * @throws IOException
     */
    @RequestMapping("/termsQuery")
    public List<Person> termsQuery() throws IOException {
        PageRequest pageRequest = PageRequest.of(0, 50);
        FieldSortBuilder idSortBuilder = SortBuilders.fieldSort("id").order(SortOrder.ASC);
        TermsQueryBuilder termsQueryBuilder = QueryBuilders.termsQuery("firstname", "vera", "kari", "blake");
        //term 需要指定为字符的小写形式
        //TermsQueryBuilder termsQueryBuilder = QueryBuilders.termsQuery("firstname", "Vera", "Kari", "Blake");
        NativeSearchQuery nativeSearchQuery = new NativeSearchQueryBuilder().withQuery(termsQueryBuilder)
                .withPageable(pageRequest)
                .withSort(idSortBuilder)
                .build();
        String query = nativeSearchQuery.getQuery().toString();
        logger.info(query);
        List<Person> content = personRepository.search(nativeSearchQuery).getContent();
        return content;
    }

    @RequestMapping("/termQuery")
    public List<Person> termQuery() throws IOException {
        PageRequest pageRequest = PageRequest.of(0, 50);
        FieldSortBuilder idSortBuilder = SortBuilders.fieldSort("id").order(SortOrder.ASC);
        TermQueryBuilder termQueryBuilder = QueryBuilders.termQuery("firstname", "vera");
        NativeSearchQuery nativeSearchQuery = new NativeSearchQueryBuilder().withQuery(termQueryBuilder)
                .withPageable(pageRequest)
                .withSort(idSortBuilder)
                .build();
        String query = nativeSearchQuery.getQuery().toString();
        logger.info(query);
        List<Person> content = personRepository.search(nativeSearchQuery).getContent();
        return content;
    }


    /**
     * 在id , age 中找包含44 的记录
     * @return
     * @throws IOException
     */
    @RequestMapping("/multimatchQuery")
    public List<Person> multimatchQuery() throws IOException {
        PageRequest pageRequest = PageRequest.of(0, 50);
        FieldSortBuilder idSortBuilder = SortBuilders.fieldSort("id").order(SortOrder.ASC);
        MultiMatchQueryBuilder multiMatchQueryBuilder = QueryBuilders.multiMatchQuery("44", "id", "age");
        NativeSearchQuery nativeSearchQuery = new NativeSearchQueryBuilder().withQuery(multiMatchQueryBuilder)
                .withPageable(pageRequest)
                .withSort(idSortBuilder)
                .build();
        String query = nativeSearchQuery.getQuery().toString();
        logger.info(query);
        List<Person> content = personRepository.search(nativeSearchQuery).getContent();
        return content;
    }

    /**
     * <pre>
    GET /person/_search
    {
        "query": {
            "bool": {
                "must": [
                {
                    "match": {
                    "firstname": "Effie"
                }
                }
          ],
                "must_not": [
                {
                    "match": {
                    "gender": "M"
                }
                }
          ],
                "should": [
                {"match": {
                    "balance": "3607"
                }}
          ]

            }
        }
    }
     *</pre>
     *
     *
     * multimatch 用于判断多个字段 进行条件的筛选
    */
    @RequestMapping("/boolQuery")
    public List<Person> boolQuery() throws IOException {
        PageRequest pageRequest = PageRequest.of(0, 50);
        FieldSortBuilder idSortBuilder = SortBuilders.fieldSort("id").order(SortOrder.ASC);
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery()
                .must(QueryBuilders.matchQuery("firstname", "Effie"))
                .mustNot(QueryBuilders.matchQuery("gender", "M"))
                .should(QueryBuilders.matchQuery("balance", "3607"));

        NativeSearchQuery nativeSearchQuery = new NativeSearchQueryBuilder().withQuery(boolQueryBuilder)
                .withPageable(pageRequest)
                .withSort(idSortBuilder)
                .build();
        String query = nativeSearchQuery.getQuery().toString();
        logger.info(query);
        List<Person> content = personRepository.search(nativeSearchQuery).getContent();
        return content;
    }


//    GET /person/_search
//    {
//        "query": {
//        "ids": {
//            "values": [
//            "25",
//                    "44",
//                    "126"
//      ]
//        }
//    }
//    }
    /**
     * 查询id : ... id 可变参数
     *
     * idsQuery的type 传递"id" 查询不到记录?
     *
     * @return
     * @throws IOException
     */
    @RequestMapping("/idsQuery")
    public List<Person> idsQuery() throws IOException {
        PageRequest pageRequest = PageRequest.of(0, 50);
        FieldSortBuilder idSortBuilder = SortBuilders.fieldSort("id").order(SortOrder.ASC);
        //传递 type对应的值
        IdsQueryBuilder idsQueryBuilder = QueryBuilders.idsQuery().addIds("25", "44", "126");
        NativeSearchQuery nativeSearchQuery = new NativeSearchQueryBuilder().withQuery(idsQueryBuilder)
                .withPageable(pageRequest)
                .withSort(idSortBuilder)
                .build();
        String query = nativeSearchQuery.getQuery().toString();
        logger.info(query);
        List<Person> content = personRepository.search(nativeSearchQuery).getContent();
        return content;
    }


    /**

     <pre>

        GET /person/_search
        {
            "query": {
            "constant_score": {
                "filter": {
                    "term": {
                        "gender": "m"
                    }
                },
                "boost": 1.2
            }
        }
        }
     </pre>
     */
    @RequestMapping("/constantScoreQuery")
    public List<Person> constantScoreQuery() throws IOException {
        PageRequest pageRequest = PageRequest.of(0, 50);
        FieldSortBuilder idSortBuilder = SortBuilders.fieldSort("id").order(SortOrder.ASC);
        ConstantScoreQueryBuilder constantScoreQueryBuilder = QueryBuilders.constantScoreQuery(QueryBuilders.termQuery("gender", "m")).boost(2.0f);
        NativeSearchQuery nativeSearchQuery = new NativeSearchQueryBuilder().withQuery(constantScoreQueryBuilder)
                .withPageable(pageRequest)
                .withSort(idSortBuilder)
                .build();
        String query = nativeSearchQuery.getQuery().toString();
        logger.info(query);
        List<Person> content = personRepository.search(nativeSearchQuery).getContent();
        return content;
    }


//    GET /person/_search
//    {
//        "query": {
//        "dis_max": {
//            "tie_breaker": 0.7,
//                    "boost": 1.2,
//                    "queries": [
//            {
//                "term": {
//                "firstname": {
//                    "value": "Effie"
//                }
//            }
//            },
//            {
//                "match": {
//                "gender": "m"
//            }
//            }
//      ]
//        }
//    }
//    }
    /***
     *相比使用bool查询,我们可以使用dis_max查询(Disjuction Max Query)。
     * Disjuction的意思"OR"(而Conjunction的意思是"AND"),
     * 因此Disjuction Max Query的意思就是返回匹配了任何查询的文档,并且分值是产生了最佳匹配的查询所对应的分值:
     *
     * @return
     * @throws IOException
     */
    @RequestMapping("/disMaxQuery")
    public List<Person> disMaxQuery() throws IOException {
        PageRequest pageRequest = PageRequest.of(0, 50);
        FieldSortBuilder idSortBuilder = SortBuilders.fieldSort("id").order(SortOrder.ASC);

        DisMaxQueryBuilder disMaxQueryBuilder = QueryBuilders.disMaxQuery()
                .add(QueryBuilders.termQuery("firstname", "Effie"))
                .add(QueryBuilders.matchQuery("gender", "m"))
                .boost(1.2f)
                .tieBreaker(0.7f);

        NativeSearchQuery nativeSearchQuery = new NativeSearchQueryBuilder().withQuery(disMaxQueryBuilder)
                .withPageable(pageRequest)
                .withSort(idSortBuilder)
                .build();
        String query = nativeSearchQuery.getQuery().toString();
        logger.info(query);
        List<Person> content = personRepository.search(nativeSearchQuery).getContent();
        return content;
    }

    /**
     * 模糊匹配
     * @return
     * @throws IOException
     */
    @RequestMapping("/fuzzyQuery")
    public List<Person> fuzzyQuery() throws IOException {
        PageRequest pageRequest = PageRequest.of(0, 50);
        FieldSortBuilder idSortBuilder = SortBuilders.fieldSort("id").order(SortOrder.ASC);

        FuzzyQueryBuilder fuzzyQueryBuilder = QueryBuilders.fuzzyQuery("firstname", "effie");

        NativeSearchQuery nativeSearchQuery = new NativeSearchQueryBuilder().withQuery(fuzzyQueryBuilder)
                .withPageable(pageRequest)
                .withSort(idSortBuilder)
                .build();
        String query = nativeSearchQuery.getQuery().toString();
        logger.info(query);
        List<Person> content = personRepository.search(nativeSearchQuery).getContent();
        return content;
    }


    //TODO
    @RequestMapping("/moreLikeThisQuery")
    public List<Person> moreLikeThisQuery() throws IOException {
        PageRequest pageRequest = PageRequest.of(0, 50);
        FieldSortBuilder idSortBuilder = SortBuilders.fieldSort("id").order(SortOrder.ASC);
        //QueryBuilders.moreLikeThisQuery({"firstname"},{"lastname"},new ,)
        NativeSearchQuery nativeSearchQuery = new NativeSearchQueryBuilder().withQuery(null)
                .withPageable(pageRequest)
                .withSort(idSortBuilder)
                .build();
        String query = nativeSearchQuery.getQuery().toString();
        logger.info(query);
        List<Person> content = personRepository.search(nativeSearchQuery).getContent();
        return content;
    }



    @RequestMapping("/prefixQuery")
    public List<Person> prefixQuery() throws IOException {
        PageRequest pageRequest = PageRequest.of(0, 50);
        FieldSortBuilder idSortBuilder = SortBuilders.fieldSort("id").order(SortOrder.ASC);
        //匹配姓名  以小写字母开头
        PrefixQueryBuilder prefixQueryBuilder = QueryBuilders.prefixQuery("firstname", "b");
        NativeSearchQuery nativeSearchQuery = new NativeSearchQueryBuilder().withQuery(prefixQueryBuilder)
                .withPageable(pageRequest)
                .withSort(idSortBuilder)
                .build();
        String query = nativeSearchQuery.getQuery().toString();
        logger.info(query);
        List<Person> content = personRepository.search(nativeSearchQuery).getContent();
        return content;
    }


    @RequestMapping("/rangeQuery")
    public List<Person> rangeQuery() throws IOException {
        PageRequest pageRequest = PageRequest.of(0, 50);
        FieldSortBuilder idSortBuilder = SortBuilders.fieldSort("id").order(SortOrder.ASC);
        RangeQueryBuilder rangeQueryBuilder = QueryBuilders.rangeQuery("age").from(20).to(30).includeLower(true).includeUpper(false);
        NativeSearchQuery nativeSearchQuery = new NativeSearchQueryBuilder().withQuery(rangeQueryBuilder)
                .withPageable(pageRequest)
                .withSort(idSortBuilder)
                .build();
        String query = nativeSearchQuery.getQuery().toString();
        logger.info(query);
        List<Person> content = personRepository.search(nativeSearchQuery).getContent();
        return content;
    }


    @RequestMapping("/spanFirstQuery")
    public List<Person> spanFirstQuery() throws IOException {
        PageRequest pageRequest = PageRequest.of(0, 50);
        FieldSortBuilder idSortBuilder = SortBuilders.fieldSort("id").order(SortOrder.ASC);
        //address: "398 Dearborn Court",  有3个term  查询court 结束的位置为 3
        SpanFirstQueryBuilder spanFirstQueryBuilder = QueryBuilders.spanFirstQuery(QueryBuilders.spanTermQuery("address", "court"), 3);
        NativeSearchQuery nativeSearchQuery = new NativeSearchQueryBuilder().withQuery(spanFirstQueryBuilder)
                .withPageable(pageRequest)
                .withSort(idSortBuilder)
                .build();
        String query = nativeSearchQuery.getQuery().toString();
        logger.info(query);
        List<Person> content = personRepository.search(nativeSearchQuery).getContent();
        return content;
    }


    @RequestMapping("/testQuery")
    public List<Person> paginationQuertestQueryy() throws IOException {
        PageRequest pageRequest = PageRequest.of(0, 10);
        FieldSortBuilder idSortBuilder = SortBuilders.fieldSort("id").order(SortOrder.ASC);

        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery()
                .must(QueryBuilders.matchQuery("gender", "f"))
                .should(QueryBuilders.termQuery("address", "court"))
                .should(QueryBuilders.termQuery("state","md"))
                .filter(QueryBuilders.rangeQuery("age").gte(30))
                .filter(QueryBuilders.rangeQuery("balance").gte(2726));

        NativeSearchQuery nativeSearchQuery = new NativeSearchQueryBuilder().withQuery(boolQueryBuilder)
                .withPageable(pageRequest)
                .withSort(idSortBuilder)
                .build();
        String query = nativeSearchQuery.getQuery().toString();
        logger.info(query);
        List<Person> content = personRepository.search(nativeSearchQuery).getContent();
        return content;
    }


    /**
     *
     *
    GET /person/_search
    {
        "query": {
            " function_score": {
                "query": {
                    "match": {
                        "gender": "F"
                    }
                },
                "field_value_factor": {
                    "field": "balance",
                            "modifier": "log1p",
                            "factor": 0.5
                }
          , "boost_mode": "sum"
            }
        }
    }
     */
    @RequestMapping("/scoreFunctionQuery")
    public List<Person> scoreFunctionQuery() throws IOException {
        PageRequest pageRequest = PageRequest.of(0, 10);
        FieldSortBuilder idSortBuilder = SortBuilders.fieldSort("id").order(SortOrder.ASC);

        //bool query
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery().must(QueryBuilders.matchQuery("gender", "F"));

        //feild_value_factor
        FieldValueFactorFunctionBuilder functionBuilder = ScoreFunctionBuilders.fieldValueFactorFunction("balance")
                .modifier(FieldValueFactorFunction.Modifier.LOG1P)
                .factor(0.5f);

        //构建builder
        FunctionScoreQueryBuilder functionScoreQueryBuilder = QueryBuilders.functionScoreQuery(boolQueryBuilder, functionBuilder).boostMode(CombineFunction.SUM);

        NativeSearchQuery nativeSearchQuery = new NativeSearchQueryBuilder().withQuery(functionScoreQueryBuilder)
                .withPageable(pageRequest)
                .withSort(idSortBuilder)
                .build();
        String query = nativeSearchQuery.getQuery().toString();
        logger.info(query);
        Page<Person> page = personRepository.search(nativeSearchQuery);
        logger.info("page: "+page.toString());
        List<Person> content = page.getContent();
        return content;
    }


    /**

     GET /person/_search
     {
         "query": {
             "function_score": {
                 "query": {
                     "match": {
                         "gender": "F"
                    }
             },
             "gauss": {
                 "balance": {
                     "origin": "43951",
                     "scale": "100",
                     "offset": "10"
                 }
             },
             "boost_mode": "sum"
             }
         }
     }
     */
    @RequestMapping("/guessQuery")
    public List<Person> guessQuery() throws IOException {
        PageRequest pageRequest = PageRequest.of(0, 10);
        FieldSortBuilder idSortBuilder = SortBuilders.fieldSort("id").order(SortOrder.ASC);

        //bool query
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery().must(QueryBuilders.matchQuery("gender", "F"));
        GaussDecayFunctionBuilder gaussDecayFunctionBuilder = ScoreFunctionBuilders.gaussDecayFunction("balance", "43951", "100", "10");

        //构建builder
        FunctionScoreQueryBuilder functionScoreQueryBuilder = QueryBuilders.functionScoreQuery(boolQueryBuilder, gaussDecayFunctionBuilder).boostMode(CombineFunction.SUM);

        NativeSearchQuery nativeSearchQuery = new NativeSearchQueryBuilder().withQuery(functionScoreQueryBuilder)
                .withPageable(pageRequest)
                //.withSort(idSortBuilder)
                .build();

        String query = nativeSearchQuery.getQuery().toString();
        logger.info(query);
        Page<Person> page = personRepository.search(nativeSearchQuery);
        logger.info("page: "+page.toString());
        List<Person> content = page.getContent();
        return content;
    }


    /**   function_score weight query
    GET /person/_search
    {
        "query": {
            "function_score": {
                    "query": {
                        "bool": {
                            "must": [
                            {
                                "match": {
                                "gender": "F"
                            }
                            },{
                                "range": {
                                    "age": {
                                        "gte": 25,
                                                "lte": 30
                                    }
                                }
                            }
                  ]
                        }
                    },
                    "functions": [
                    {
                        "weight": 2
                    }
                ]
            }
        }
    }
     **/
    @RequestMapping("/weighQuery")
    public List<Person> weighQuery() throws IOException {
        PageRequest pageRequest = PageRequest.of(0, 10);
        FieldSortBuilder idSortBuilder = SortBuilders.fieldSort("id").order(SortOrder.ASC);

        //bool query
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery()
                .must(QueryBuilders.matchQuery("gender", "F"))
                .must(QueryBuilders.rangeQuery("age").gte(25).lte(30));

        //weight buil
        WeightBuilder weightBuilder = ScoreFunctionBuilders.weightFactorFunction(2.0f);

        //构建builder
        FunctionScoreQueryBuilder functionScoreQueryBuilder = QueryBuilders.functionScoreQuery(boolQueryBuilder, weightBuilder).boostMode(CombineFunction.SUM);

        NativeSearchQuery nativeSearchQuery = new NativeSearchQueryBuilder().withQuery(functionScoreQueryBuilder)
                .withPageable(pageRequest)
                //.withSort(idSortBuilder)
                .build();

        String query = nativeSearchQuery.getQuery().toString();
        logger.info(query);
        Page<Person> page = personRepository.search(nativeSearchQuery);
        logger.info("page: "+page.toString());
        List<Person> content = page.getContent();
        return content;
    }
}

代码寄托在github:https://github.com/ninuxGithub/spring-boot-dubbo-zookeeper.git