赞
踩
目录
不分词模糊搜索:wildcardQuery与matchPhraseQuery
后续待补充:queryStringQuery,minimumShouldMatch,对检索结果中的关键词进行高亮
测试环境:
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter</artifactId>
- <version>2.0.6.RELEASE</version>
- </dependency>
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-test</artifactId>
- <scope>test</scope>
- <version>2.0.6.RELEASE</version>
- </dependency>
- <dependency>
- <groupId>org.elasticsearch.client</groupId>
- <artifactId>elasticsearch-rest-high-level-client</artifactId>
- <version>7.3.0</version>
- <exclusions>
- <exclusion>
- <groupId>org.elasticsearch</groupId>
- <artifactId>elasticsearch</artifactId>
- </exclusion>
- </exclusions>
- </dependency>
- <dependency>
- <groupId>org.elasticsearch</groupId>
- <artifactId>elasticsearch</artifactId>
- <version>7.3.0</version>
- </dependency>
2配置 application.yml
- spring:
- application:
- name: service-search
- eslearn:
- elasticsearch:
- hostlist: 127.0.0.1:9200 #多个结点中间用逗号分隔
3主类代码
- @SpringBootApplication
- public class SearchApplication {
- public static void main(String[] args) {
- SpringApplication.run(SearchApplication.class,args);
- }
- }
配置类:
- package com.learn.es.cofig;
-
- import org.apache.http.HttpHost;
- import org.elasticsearch.client.RestClient;
- import org.elasticsearch.client.RestHighLevelClient;
- import org.springframework.beans.factory.annotation.Value;
- import org.springframework.context.annotation.Bean;
- import org.springframework.context.annotation.Configuration;
-
- /**
- * @author LJM
- * @create 2022/12/10
- */
- @Configuration
- public class ElasticSearchConfig {
-
- @Value("${eslearn.elasticsearch.hostlist}")
- private String hostList;
-
- @Bean(destroyMethod = "close") //表示连接使用完成后需要关闭
- public RestHighLevelClient restHighLevelClient(){
- String[] split = hostList.split(",");
- //这种写法是考虑到可能会配置多个es节点
- HttpHost[] httpHosts = new HttpHost[split.length];
- for (int i = 0; i < split.length; i++) {
- String item = split[i];
- httpHosts[i] = new HttpHost(item.split(":")[0],Integer.parseInt(item.split(":")[1]),"http");
- }
-
- return new RestHighLevelClient(RestClient.builder(httpHosts));
- }
-
- }
测试项目结构:
在kibana中把数据插入es中:
- delete book //先删除索引
-
- PUT /book //往索引中插入数据进行测试,后面在api实现搜索的小节,可以使用从数据库中读取数据 然后把数据插入es库指定的索引
-
- PUT /book/_doc/1
- {
- "name": "Bootstrap开发",
- "description": "Bootstrap是由Twitter推出的一个前台页面开发css框架,是一个非常流行的开发框架,此框架集成了多种页面效果。此开发框架包含了大量的CSS、JS程序代码,可以帮助开发者(尤其是不擅长css页面开发的程序人员)轻松的实现一个css,不受浏览器限制的精美界面css效果。",
- "studymodel": "201002",
- "price":38.6,
- "timestamp":"2019-08-25 19:11:35",
- "pic":"group1/M00/00/00/wKhlQFs6RCeAY0pHAAJx5ZjNDEM428.jpg",
- "tags": [ "bootstrap", "dev"]
- }
-
-
- PUT /book/_doc/2
- {
- "name": "java编程思想",
- "description": "java语言是世界第一编程语言,在软件开发领域使用人数最多。",
- "studymodel": "201001",
- "price":68.6,
- "timestamp":"2019-08-25 19:11:35",
- "pic":"group1/M00/00/00/wKhlQFs6RCeAY0pHAAJx5ZjNDEM428.jpg",
- "tags": [ "java", "dev"]
- }
-
-
-
-
- PUT /book/_doc/3
- {
- "name": "spring开发基础",
- "description": "spring 在java领域非常流行,java程序员都在用。",
- "studymodel": "201001",
- "price":88.6,
- "timestamp":"2019-08-24 19:11:35",
- "pic":"group1/M00/00/00/wKhlQFs6RCeAY0pHAAJx5ZjNDEM428.jpg",
- "tags": [ "spring", "java"]
- }
测试类代码结构:
- /**
- * @author LJM
- * @create 2022/12/13
- * 测试使用java代码实现es的各种搜索
- */
- @SpringBootTest(classes = SearchApplication.class)
- @RunWith(SpringRunner.class)
- public class TestSearch {
- @Autowired
- RestHighLevelClient client;
-
- // 后面的测试方法会全部写在这个类中 .....
-
- }
在kibana中 GET /book/_search 先获取一下本地es库中的book索引下有多少数据。
- /**
- * 搜索全部
- * GET book/_search
- * {
- * "query": {
- * "match_all": {}
- * }
- * }
- * @throws IOException
- */
- @Test
- public void testSearchAll() throws IOException {
-
- //1构建搜索请求 实际生产环境中这个索引名称的获取:①把这个索引名称写在枚举类中,然后从枚举类中获取②从配置文件中获取
- SearchRequest searchRequest = new SearchRequest("book");
-
- SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
- searchSourceBuilder.query(QueryBuilders.matchAllQuery());
-
- //获取某些字段
- searchSourceBuilder.fetchSource(new String[]{"name"}, new String[]{});
-
- searchRequest.source(searchSourceBuilder);
-
- //2执行搜索
- SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);
-
- //3获取结果
- SearchHits hits = searchResponse.getHits();
-
- //数据数据
- SearchHit[] searchHits = hits.getHits();
- System.out.println("--------------------------");
- for (SearchHit hit : searchHits) {
- String id = hit.getId();
- float score = hit.getScore();
- //这个source里面就是我们存储的数据
- Map<String, Object> sourceAsMap = hit.getSourceAsMap();
- String name = (String) sourceAsMap.get("name");
- String description = (String) sourceAsMap.get("description");
- Double price = (Double) sourceAsMap.get("price");
- System.out.println("id:" + id);
- System.out.println("score:" + score);
- System.out.println("name:" + name);
- System.out.println("description:" + description);
- System.out.println("price:" + price);
- System.out.println("==========================");
-
- }
- }
- /**
- * 通过ids进行搜索 有的就查询出来,没有的也不会报错
- * GET /book/_search
- * {
- * "query": {
- * "ids" : {
- * "values" : ["1", "2", "6"]
- * }
- * }
- * }
- * @throws IOException
- */
- @Test
- public void testSearchIds() throws IOException {
-
- //1构建搜索请求
- SearchRequest searchRequest = new SearchRequest("book");
-
- SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
- searchSourceBuilder.query(QueryBuilders.idsQuery().addIds("1","2","6"));
-
- searchRequest.source(searchSourceBuilder);
-
- //2执行搜索
- SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);
-
- //3获取结果
- SearchHits hits = searchResponse.getHits();
-
- //数据数据
- SearchHit[] searchHits = hits.getHits();
- System.out.println("--------------------------");
- for (SearchHit hit : searchHits) {
- String id = hit.getId();
- float score = hit.getScore();
- //这个source里面就是我们存储的数据
- Map<String, Object> sourceAsMap = hit.getSourceAsMap();
- String name = (String) sourceAsMap.get("name");
- String description = (String) sourceAsMap.get("description");
- Double price = (Double) sourceAsMap.get("price");
- System.out.println("id:" + id);
- System.out.println("name:" + name);
- System.out.println("description:" + description);
- System.out.println("price:" + price);
- System.out.println("==========================");
-
- }
- }
- /**
- * 对搜索结果进行分页
- * GET book/_search
- * {
- * "query": {
- * "match_all": {}
- * },
- * "from": 0,
- * "size": 2
- * }
- */
- @Test
- public void testSearchPage() throws IOException {
- //1构建搜索请求
- SearchRequest searchRequest = new SearchRequest("book");
-
- SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
- searchSourceBuilder.query(QueryBuilders.matchAllQuery());
-
- //搜索第几页的数据
- int page=1;
- //每页展示几个数据
- //int size=2; //因为本地es一共就插入了三条数据进行测试,所以可以把大小分别设置为2和3看一下输出效果
- int size=3;
- //下标计算
- int from = (page-1) / size;
-
- searchSourceBuilder.from(from);
- searchSourceBuilder.size(size);
-
- searchRequest.source(searchSourceBuilder);
-
- //2执行搜索
- SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);
-
- //3获取结果
- SearchHits hits = searchResponse.getHits();
-
- //数据数据
- SearchHit[] searchHits = hits.getHits();
- System.out.println("--------------------------");
- for (SearchHit hit : searchHits) {
- String id = hit.getId();
- float score = hit.getScore();
- //这个source里面就是我们存储的数据
- Map<String, Object> sourceAsMap = hit.getSourceAsMap();
- String name = (String) sourceAsMap.get("name");
- String description = (String) sourceAsMap.get("description");
- Double price = (Double) sourceAsMap.get("price");
- System.out.println("id:" + id);
- System.out.println("name:" + name);
- System.out.println("description:" + description);
- System.out.println("price:" + price);
- System.out.println("==========================");
-
- }
- }
- /**
- * match搜索 这个是会进行分词搜索的
- * GET /book/_search
- * {
- * "query": {
- * "match": {
- * "description": "java程序员"
- * }
- * }
- * }
- * @throws IOException
- */
- @Test
- public void testSearchMatch() throws IOException {
- //1构建搜索请求
- SearchRequest searchRequest = new SearchRequest("book");
-
- SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
- searchSourceBuilder.query(QueryBuilders.matchQuery("description", "java程序员"));
-
-
- searchRequest.source(searchSourceBuilder);
-
- //2执行搜索
- SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);
-
- //3获取结果
- SearchHits hits = searchResponse.getHits();
-
- //数据数据
- SearchHit[] searchHits = hits.getHits();
- System.out.println("--------------------------");
- for (SearchHit hit : searchHits) {
- String id = hit.getId();
- float score = hit.getScore();
- //这个source里面就是我们存储的数据
- Map<String, Object> sourceAsMap = hit.getSourceAsMap();
- String name = (String) sourceAsMap.get("name");
- String description = (String) sourceAsMap.get("description");
- Double price = (Double) sourceAsMap.get("price");
- System.out.println("id:" + id);
- System.out.println("name:" + name);
- System.out.println("description:" + description);
- System.out.println("price:" + price);
- System.out.println("==========================");
-
- }
- }
- /**
- * 不分词模糊搜索 like '%检索词%'
- * @throws IOException
- */
- @Test
- public void testSearchLike() throws IOException {
- //1构建搜索请求
- SearchRequest searchRequest = new SearchRequest("book");
-
- SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
- //使用matchPhraseQuery 需要对检索的关键词的前后加 * 否则不是完全的模糊匹配 可以对检索的结果中的检索关键词进行高亮
- searchSourceBuilder.query(QueryBuilders.matchPhraseQuery("description", "*"+"程序员"+"*"));
-
- //还可以使用wildcardQuery 但是这种就会导致检索的结果不能高亮(这个不太确定,但是我自己试的时候,这样确实是不能对检索结果中的检索词进行高亮)
- //需要在检索的字段名后拼接 ".keyword" 并且也需要对检索词前后添加 *
- // searchSourceBuilder.query(QueryBuilders.wildcardQuery("description"+".keyword","*"+"程序员"+"*"));
-
-
-
- searchRequest.source(searchSourceBuilder);
-
- //2执行搜索
- SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);
-
- //3获取结果
- SearchHits hits = searchResponse.getHits();
-
- //数据数据
- SearchHit[] searchHits = hits.getHits();
- System.out.println("--------------------------");
- for (SearchHit hit : searchHits) {
- String id = hit.getId();
- float score = hit.getScore();
- //这个source里面就是我们存储的数据
- Map<String, Object> sourceAsMap = hit.getSourceAsMap();
- String name = (String) sourceAsMap.get("name");
- String description = (String) sourceAsMap.get("description");
- Double price = (Double) sourceAsMap.get("price");
- System.out.println("id:" + id);
- System.out.println("name:" + name);
- System.out.println("description:" + description);
- System.out.println("price:" + price);
- System.out.println("==========================");
-
- }
- }
- /**
- * term 搜索 如果字段为keyword那么【存储】和【搜索】都不分词。 搜索的时候相当于在使用 = 符号进行搜索
- * GET / book / _search
- * {
- * "query":{
- * "term":{
- * "description":"java程序员"
- * }
- * }
- * }
- * @throws IOException
- */
- @Test
- public void testSearchTerm() throws IOException {
-
- //1构建搜索请求
- SearchRequest searchRequest = new SearchRequest("book");
-
- SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
- //如果字段的映射是text但是也想要精确匹配,可以这样操作:QueryBuilders.termQuery("description" + ".keyword","java程序员")
- searchSourceBuilder.query(QueryBuilders.termQuery("description", "java语言"));
-
- searchRequest.source(searchSourceBuilder);
-
- //2执行搜索
- SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);
-
- //3获取结果
- SearchHits hits = searchResponse.getHits();
-
- //数据数据
- SearchHit[] searchHits = hits.getHits();
- System.out.println("--------------------------");
- for (SearchHit hit : searchHits) {
- String id = hit.getId();
- float score = hit.getScore();
- //这个source里面就是我们存储的数据
- Map<String, Object> sourceAsMap = hit.getSourceAsMap();
- String name = (String) sourceAsMap.get("name");
- String description = (String) sourceAsMap.get("description");
- Double price = (Double) sourceAsMap.get("price");
- System.out.println("id:" + id);
- System.out.println("name:" + name);
- System.out.println("description:" + description);
- System.out.println("price:" + price);
- System.out.println("==========================");
-
- }
- }
- /**
- * multi_match搜索
- * GET /book/_search
- * {
- * "query": {
- * "multi_match": {
- * "query": "java程序员",
- * "fields": ["name", "description"]
- * }
- * }
- * }
- * @throws IOException
- */
- @Test
- public void testSearchMultiMatch() throws IOException {
-
- //1构建搜索请求
- SearchRequest searchRequest = new SearchRequest("book");
-
- SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
- //第二个参数才是 字段 第一个参数是匹配的内容
- searchSourceBuilder.query(QueryBuilders.multiMatchQuery("java程序员","name","description"));
-
- searchRequest.source(searchSourceBuilder);
-
- //2执行搜索
- SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);
-
- //3获取结果
- SearchHits hits = searchResponse.getHits();
-
- //数据数据
- SearchHit[] searchHits = hits.getHits();
- System.out.println("--------------------------");
- for (SearchHit hit : searchHits) {
- String id = hit.getId();
- float score = hit.getScore();
- //这个source里面就是我们存储的数据
- Map<String, Object> sourceAsMap = hit.getSourceAsMap();
- String name = (String) sourceAsMap.get("name");
- String description = (String) sourceAsMap.get("description");
- Double price = (Double) sourceAsMap.get("price");
- System.out.println("id:" + id);
- System.out.println("name:" + name);
- System.out.println("description:" + description);
- System.out.println("price:" + price);
- System.out.println("==========================");
-
- }
- }
- /**
- * bool搜索 多条件匹配 and or !=
- * GET / book / _search
- * {
- * "query":{
- * "bool":{
- * "must": [
- * {
- * "multi_match":{
- * "query":"java程序员",
- * "fields": ["name", "description"]
- * }
- * }
- * ],
- * "should": [
- * {
- * "match":{
- * "studymodel":"201001"
- * }
- * }
- * ]
- * }
- * }
- * }
- * @throws IOException
- */
- @Test
- public void testSearchBool() throws IOException {
-
- //1构建搜索请求
- SearchRequest searchRequest = new SearchRequest("book");
-
- SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
-
- //构建multiMatch请求 第一个参数是检索内容 第二个参数是检索的字段
- MultiMatchQueryBuilder multiMatchQueryBuilder = QueryBuilders.multiMatchQuery("java程序员", "name", "description");
- //构建match请求
- MatchQueryBuilder matchQueryBuilder = QueryBuilders.matchQuery("name", "测试没有的字段");
-
- BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
- boolQueryBuilder.must(multiMatchQueryBuilder);
- boolQueryBuilder.should(matchQueryBuilder);
- // boolQueryBuilder.must(matchQueryBuilder); //把should改成must就相当于用 and进行了再一次的过滤 就会查询不到数据
-
- searchSourceBuilder.query(boolQueryBuilder);
- searchRequest.source(searchSourceBuilder);
-
- //2执行搜索
- SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);
-
- //3获取结果
- SearchHits hits = searchResponse.getHits();
-
- //数据数据
- SearchHit[] searchHits = hits.getHits();
- System.out.println("--------------------------");
- for (SearchHit hit : searchHits) {
- String id = hit.getId();
- float score = hit.getScore();
- //这个source里面就是我们存储的数据
- Map<String, Object> sourceAsMap = hit.getSourceAsMap();
- String name = (String) sourceAsMap.get("name");
- String description = (String) sourceAsMap.get("description");
- Double price = (Double) sourceAsMap.get("price");
- System.out.println("id:" + id);
- System.out.println("name:" + name);
- System.out.println("description:" + description);
- System.out.println("price:" + price);
- System.out.println("==========================");
-
- }
- }
-
- }
过滤搜索和范围搜索的区别:
filter,仅仅只是按照搜索条件过滤出需要的数据而已,不计算任何相关度分数,对相关度没有任何影响。
query,会去计算每个document相对于搜索条件的相关度,并按照相关度进行排序。
- /**
- * filter过滤搜索
- * GET /book/_search
- * {
- * "query": {
- * "bool": {
- * "must": [
- * {
- * "multi_match": {
- * "query": "java程序员",
- * "fields": ["name","description"]
- * }
- * }
- * ],
- * "should": [
- * {
- * "match": {
- * "studymodel": "201001"
- * }
- * }
- * ],
- * "filter": {
- * "range": {
- * "price": {
- * "gte": 50,
- * "lte": 90
- * }
- * }
- *
- * }
- * }
- * }
- * }
- * @throws IOException
- */
- @Test
- public void testSearchFilter() throws IOException {
-
- //1构建搜索请求
- SearchRequest searchRequest = new SearchRequest("book");
-
- SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
-
- //构建multiMatch请求
- MultiMatchQueryBuilder multiMatchQueryBuilder = QueryBuilders.multiMatchQuery("java程序员", "name", "description");
- //构建match请求
- MatchQueryBuilder matchQueryBuilder = QueryBuilders.matchQuery("studymodel", "201001");
-
- BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
- boolQueryBuilder.must(multiMatchQueryBuilder);
- boolQueryBuilder.should(matchQueryBuilder);
-
- boolQueryBuilder.filter(QueryBuilders.rangeQuery("price").gte(50).lte(90));
-
- searchSourceBuilder.query(boolQueryBuilder);
-
- searchRequest.source(searchSourceBuilder);
-
- //2执行搜索
- SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);
-
- //3获取结果
- SearchHits hits = searchResponse.getHits();
-
- //数据数据
- SearchHit[] searchHits = hits.getHits();
- System.out.println("--------------------------");
- for (SearchHit hit : searchHits) {
- String id = hit.getId();
- float score = hit.getScore();
- //这个source里面就是我们存储的数据
- Map<String, Object> sourceAsMap = hit.getSourceAsMap();
- String name = (String) sourceAsMap.get("name");
- String description = (String) sourceAsMap.get("description");
- Double price = (Double) sourceAsMap.get("price");
- System.out.println("id:" + id);
- System.out.println("name:" + name);
- System.out.println("description:" + description);
- System.out.println("price:" + price);
- System.out.println("==========================");
-
- }
- }
- /**
- * sort排序搜索
- * GET /book/_search
- * {
- * "query": {
- * "bool": {
- * "must": [
- * {
- * "multi_match": {
- * "query": "java程序员",
- * "fields": ["name","description"]
- * }
- * }
- * ],
- * "should": [
- * {
- * "match": {
- * "studymodel": "201001"
- * }
- * }
- * ],
- * "filter": {
- * "range": {
- * "price": {
- * "gte": 50,
- * "lte": 90
- * }
- * }
- *
- * }
- * }
- * },
- * "sort": [
- * {
- * "price": {
- * "order": "asc"
- * }
- * }
- * ]
- * }
- * @throws IOException
- */
- @Test
- public void testSearchSort() throws IOException {
-
- //1构建搜索请求
- SearchRequest searchRequest = new SearchRequest("book");
-
- SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
-
- //构建multiMatch请求
- MultiMatchQueryBuilder multiMatchQueryBuilder = QueryBuilders.multiMatchQuery("java程序员", "name", "description");
- //构建match请求
- MatchQueryBuilder matchQueryBuilder = QueryBuilders.matchQuery("studymodel", "201001");
-
- BoolQueryBuilder boolQueryBuilder=QueryBuilders.boolQuery();
- boolQueryBuilder.must(multiMatchQueryBuilder);
- boolQueryBuilder.should(matchQueryBuilder);
-
- boolQueryBuilder.filter(QueryBuilders.rangeQuery("price").gte(50).lte(90));
-
- searchSourceBuilder.query(boolQueryBuilder);
-
- //按照价格升序
- searchSourceBuilder.sort("price", SortOrder.ASC);
-
-
- searchRequest.source(searchSourceBuilder);
-
- //2执行搜索
- SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);
-
- //3获取结果
- SearchHits hits = searchResponse.getHits();
-
- //数据数据
- SearchHit[] searchHits = hits.getHits();
- System.out.println("--------------------------");
- for (SearchHit hit : searchHits) {
- String id = hit.getId();
- float score = hit.getScore();
- //这个source里面就是我们存储的数据
- Map<String, Object> sourceAsMap = hit.getSourceAsMap();
- String name = (String) sourceAsMap.get("name");
- String description = (String) sourceAsMap.get("description");
- Double price = (Double) sourceAsMap.get("price");
- System.out.println("id:" + id);
- System.out.println("name:" + name);
- System.out.println("description:" + description);
- System.out.println("price:" + price);
- System.out.println("==========================");
- }
- }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。