【Elasticsearch】搜索类型介绍,以及使用SpringBoot实现,并展现给前端

Elasticsearch 提供了多种查询类型,每种查询类型适用于不同的搜索场景。以下是八种常见的 Elasticsearch 查询类型及其详细说明和示例。

1. Match Query

用途 :用于全文搜索,会对输入的文本进行分词,并在索引中的字段中查找这些分词。 特点:支持模糊匹配、短语匹配等。

示例

json

复制代码
GET /my_index/_search
{
  "query": {
    "match": {
      "content": "quick brown fox"
    }
  }
}

2. Term Query

用途 :用于精确匹配,不会对输入的文本进行分词。 特点:适用于关键词、ID 等不需要分词的情况。

示例

json

复制代码
GET /my_index/_search
{
  "query": {
    "term": {
      "status": "active"
    }
  }
}

3. Terms Query

用途 :用于在一个字段上匹配多个值。 特点:类似于 SQL 中的 IN 操作符。

示例

json

复制代码
GET /my_index/_search
{
  "query": {
    "terms": {
      "tags": ["news", "sports"]
    }
  }
}

4. Range Query

用途 :用于范围查询,可以指定数值或日期范围。 特点:适用于数值型字段和日期字段。

示例

json

复制代码
GET /my_index/_search
{
  "query": {
    "range": {
      "age": {
        "gte": 18,
        "lte": 30
      }
    }
  }
}

5. Bool Query

用途 :组合多个查询条件,支持 must(必须满足)、should(应该满足)、must_not(必须不满足)和 filter(过滤)子句。 特点:灵活性高,可以构建复杂的查询逻辑。

示例

json

复制代码
GET /my_index/_search
{
  "query": {
    "bool": {
      "must": [
        { "match": { "title": "Elasticsearch" } },
        { "range": { "date": { "gte": "now-1y/d" }}}
      ],
      "filter": [
        { "term": { "status": "published" }}
      ]
    }
  }
}

6. Wildcard Query

用途 :使用通配符进行匹配。 特点 :支持 *? 通配符,但性能较差,应谨慎使用。

示例

json

复制代码
GET /my_index/_search
{
  "query": {
    "wildcard": {
      "name": "joh*"
    }
  }
}

7. Fuzzy Query

用途 :用于近似匹配,允许一定数量的拼写错误。 特点:适用于拼写错误较多的搜索场景。

示例
复制代码
GET /my_index/_search
{
  "query": {
    "fuzzy": {
      "username": {
        "value": "kenneth",
        "fuzziness": "AUTO"
      }
    }
  }
}

8. Match Phrase Query

用途 :用于精确匹配整个短语。 特点:不会对短语进行分词,要求短语完全一致。

示例

json

复制代码
GET /my_index/_search
{
  "query": {
    "match_phrase": {
      "description": "Elasticsearch search engine"
    }
  }
}

总结

每种查询类型都有其特定的应用场景和优缺点:

  • Match Query:适合全文搜索。
  • Term Query:适合精确匹配。
  • Terms Query:适合多值匹配。
  • Range Query:适合范围查询。
  • Bool Query:适合复杂查询逻辑。
  • Wildcard Query:适合通配符匹配,性能较低。
  • Fuzzy Query:适合拼写错误匹配。
  • Match Phrase Query:适合精确短语匹配。

通过合理选择和组合这些查询类型,可以实现高效且灵活的搜索功能。

参考资料

这些资源提供了更多关于 Elasticsearch 查询类型的详细信息和示例,帮助你更好地理解和使用这些查询

为了实现八种 Elasticsearch 查询类型并在 Web 前端展示结果,我们可以使用 Spring Boot 构建后端服务,并使用 Thymeleaf 作为模板引擎来构建前端页面。以下是一个完整的示例,展示如何实现这八种查询类型并将结果显示在 Web 前端。

项目结构

复制代码
spring-boot-elasticsearch-demo/
├── src/
│   ├── main/
│   │   ├── java/
│   │   │   └── com/
│   │   │       └── example/
│   │   │           ├── controller/
│   │   │           │   └── SearchController.java
│   │   │           ├── model/
│   │   │           │   └── Document.java
│   │   │           ├── repository/
│   │   │           │   └── DocumentRepository.java
│   │   │           ├── service/
│   │   │           │   └── SearchService.java
│   │   │           └── SpringBootElasticsearchDemoApplication.java
│   │   └── resources/
│   │       ├── application.yml
│   │       ├── static/
│   │       └── templates/
│   │           └── search.html
├── pom.xml

1. 添加依赖

pom.xml 中添加必要的依赖:

xml

XML 复制代码
<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-elasticsearch</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-thymeleaf</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <optional>true</optional>
    </dependency>
    <dependency>
        <groupId>org.elasticsearch.client</groupId>
        <artifactId>elasticsearch-rest-high-level-client</artifactId>
        <version>7.6.2</version>
    </dependency>
</dependencies>

2. 配置文件

src/main/resources/application.yml 中配置 Elasticsearch 连接信息:

yaml

XML 复制代码
spring:
  elasticsearch:
    rest:
      uris: http://localhost:9200

server:
  port: 8080

3. 实体类

创建一个实体类 Document.java 表示索引中的文档:

java

java 复制代码
package com.example.model;

import lombok.Data;
import org.springframework.data.annotation.Id;
import org.springframework.data.elasticsearch.annotations.Document;
import org.springframework.data.elasticsearch.annotations.Field;
import org.springframework.data.elasticsearch.annotations.FieldType;

@Data
@Document(indexName = "documents")
public class Document {
    @Id
    private String id;

    @Field(type = FieldType.Text)
    private String title;

    @Field(type = FieldType.Text)
    private String content;

    @Field(type = FieldType.Integer)
    private Integer age;

    @Field(type = FieldType.Date)
    private String date;

    @Field(type = FieldType.Keyword)
    private String status;

    @Field(type = FieldType.Keyword)
    private String[] tags;

    @Field(type = FieldType.Keyword)
    private String username;
}

4. Repository 接口

创建一个 Repository 接口 DocumentRepository.java

java

java 复制代码
package com.example.repository;

import com.example.model.Document;
import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;

public interface DocumentRepository extends ElasticsearchRepository<Document, String> {
}

5. Service 层

创建一个 Service 类 SearchService.java 来处理各种查询逻辑:

java

java 复制代码
package com.example.service;

import com.example.model.Document;
import com.example.repository.DocumentRepository;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.index.query.*;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

@Service
public class SearchService {

    @Autowired
    private RestHighLevelClient client;

    public List<Document> matchQuery(String field, String query) throws IOException {
        SearchRequest searchRequest = new SearchRequest("documents");
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        MatchQueryBuilder matchQueryBuilder = QueryBuilders.matchQuery(field, query);
        sourceBuilder.query(matchQueryBuilder);
        searchRequest.source(sourceBuilder);
        SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);
        return getDocumentsFromResponse(searchResponse);
    }

    public List<Document> termQuery(String field, String value) throws IOException {
        SearchRequest searchRequest = new SearchRequest("documents");
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        TermQueryBuilder termQueryBuilder = QueryBuilders.termQuery(field, value);
        sourceBuilder.query(termQueryBuilder);
        searchRequest.source(sourceBuilder);
        SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);
        return getDocumentsFromResponse(searchResponse);
    }

    public List<Document> termsQuery(String field, List<String> values) throws IOException {
        SearchRequest searchRequest = new SearchRequest("documents");
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        TermsQueryBuilder termsQueryBuilder = QueryBuilders.termsQuery(field, values);
        sourceBuilder.query(termsQueryBuilder);
        searchRequest.source(sourceBuilder);
        SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);
        return getDocumentsFromResponse(searchResponse);
    }

    public List<Document> rangeQuery(String field, Object gte, Object lte) throws IOException {
        SearchRequest searchRequest = new SearchRequest("documents");
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        RangeQueryBuilder rangeQueryBuilder = QueryBuilders.rangeQuery(field).gte(gte).lte(lte);
        sourceBuilder.query(rangeQueryBuilder);
        searchRequest.source(sourceBuilder);
        SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);
        return getDocumentsFromResponse(searchResponse);
    }

    public List<Document> boolQuery(Map<String, Object> mustQueries, Map<String, Object> shouldQueries, Map<String, Object> mustNotQueries) throws IOException {
        SearchRequest searchRequest = new SearchRequest("documents");
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();

        if (mustQueries != null) {
            for (Map.Entry<String, Object> entry : mustQueries.entrySet()) {
                boolQueryBuilder.must(QueryBuilders.matchQuery(entry.getKey(), entry.getValue()));
            }
        }

        if (shouldQueries != null) {
            for (Map.Entry<String, Object> entry : shouldQueries.entrySet()) {
                boolQueryBuilder.should(QueryBuilders.matchQuery(entry.getKey(), entry.getValue()));
            }
        }

        if (mustNotQueries != null) {
            for (Map.Entry<String, Object> entry : mustNotQueries.entrySet()) {
                boolQueryBuilder.mustNot(QueryBuilders.matchQuery(entry.getKey(), entry.getValue()));
            }
        }

        sourceBuilder.query(boolQueryBuilder);
        searchRequest.source(sourceBuilder);
        SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);
        return getDocumentsFromResponse(searchResponse);
    }

    public List<Document> wildcardQuery(String field, String value) throws IOException {
        SearchRequest searchRequest = new SearchRequest("documents");
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        WildcardQueryBuilder wildcardQueryBuilder = QueryBuilders.wildcardQuery(field, value);
        sourceBuilder.query(wildcardQueryBuilder);
        searchRequest.source(sourceBuilder);
        SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);
        return getDocumentsFromResponse(searchResponse);
    }

    public List<Document> fuzzyQuery(String field, String value) throws IOException {
        SearchRequest searchRequest = new SearchRequest("documents");
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        FuzzyQueryBuilder fuzzyQueryBuilder = QueryBuilders.fuzzyQuery(field, value);
        sourceBuilder.query(fuzzyQueryBuilder);
        searchRequest.source(sourceBuilder);
        SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);
        return getDocumentsFromResponse(searchResponse);
    }

    public List<Document> matchPhraseQuery(String field, String phrase) throws IOException {
        SearchRequest searchRequest = new SearchRequest("documents");
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        MatchPhraseQueryBuilder matchPhraseQueryBuilder = QueryBuilders.matchPhraseQuery(field, phrase);
        sourceBuilder.query(matchPhraseQueryBuilder);
        searchRequest.source(sourceBuilder);
        SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);
        return getDocumentsFromResponse(searchResponse);
    }

    private List<Document> getDocumentsFromResponse(SearchResponse searchResponse) {
        List<Document> documents = new ArrayList<>();
        searchResponse.getHits().forEach(hit -> {
            Document document = new Document();
            document.setId(hit.getId());
            document.setTitle((String) hit.getSourceAsMap().get("title"));
            document.setContent((String) hit.getSourceAsMap().get("content"));
            document.setAge((Integer) hit.getSourceAsMap().get("age"));
            document.setDate((String) hit.getSourceAsMap().get("date"));
            document.setStatus((String) hit.getSourceAsMap().get("status"));
            document.setTags((String[]) hit.getSourceAsMap().get("tags"));
            document.setUsername((String) hit.getSourceAsMap().get("username"));
            documents.add(document);
        });
        return documents;
    }
}

6. Controller 层

创建一个 Controller 类 SearchController.java 来处理 HTTP 请求并返回结果:

java

java 复制代码
package com.example.controller;

import com.example.model.Document;
import com.example.service.SearchService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;

import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Controller
public class SearchController {

    @Autowired
    private SearchService searchService;

    @GetMapping("/search")
    public String search(
            @RequestParam(required = false) String queryType,
            @RequestParam(required = false) String field,
            @RequestParam(required = false) String query,
            @RequestParam(required = false) String value,
            @RequestParam(required = false) String gte,
            @RequestParam(required = false) String lte,
            @RequestParam(required = false) String[] values,
            Model model) throws IOException {

        List<Document> results = null;

        switch (queryType) {
            case "match":
                results = searchService.matchQuery(field, query);
                break;
            case "term":
                results = searchService.termQuery(field, value);
                break;
            case "terms":
                results = searchService.termsQuery(field, List.of(values));
                break;
            case "range":
                results = searchService.rangeQuery(field, gte, lte);
                break;
            case "bool":
                Map<String, Object> mustQueries = new HashMap<>();
                Map<String, Object> shouldQueries = new HashMap<>();
                Map<String, Object> mustNotQueries = new HashMap<>();

                if (field != null && query != null) {
                    mustQueries.put(field, query);
                }

                results = searchService.boolQuery(mustQueries, shouldQueries, mustNotQueries);
                break;
            case "wildcard":
                results = searchService.wildcardQuery(field, value);
                break;
            case "fuzzy":
                results = searchService.fuzzyQuery(field, value);
                break;
            case "match_phrase":
                results = searchService.matchPhraseQuery(field, query);
                break;
            default:
                // Handle default case or throw an exception
                break;
        }

        model.addAttribute("results", results);
        return "search";
    }
}

7. 前端页面

创建一个 Thymeleaf 模板 search.html 来展示搜索结果:

html

html 复制代码
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Elasticsearch Queries</title>
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css">
</head>
<body>
<div class="container mt-5">
    <h1>Elasticsearch Queries</h1>
    <form method="get" action="/search">
        <div class="form-group">
            <label for="queryType">Query Type:</label>
            <select class="form-control" id="queryType" name="queryType">
                <option value="match">Match</option>
                <option value="term">Term</option>
                <option value="terms">Terms</option>
                <option value="range">Range</option>
                <option value="bool">Bool</option>
                <option value="wildcard">Wildcard</option>
                <option value="fuzzy">Fuzzy</option>
                <option value="match_phrase">Match Phrase</option>
            </select>
        </div>
        <div class="form-group">
            <label for="field">Field:</label>
            <input type="text" class="form-control" id="field" name="field">
        </div>
        <div class="form-group">
            <label for="query">Query:</label>
            <input type="text" class="form-control" id="query" name="query">
        </div>
        <div class="form-group">
            <label for="value">Value:</label>
            <input type="text" class="form-control" id="value" name="value">
        </div>
        <div class="form-group">
            <label for="gte">GTE:</label>
            <input type="text" class="form-control" id="gte" name="gte">
        </div>
        <div class="form-group">
            <label for="lte">LTE:</label>
            <input type="text" class="form-control" id="lte" name="lte">
        </div>
        <div class="form-group">
            <label for="values">Values (comma separated):</label>
            <input type="text" class="form-control" id="values" name="values">
        </div>
        <button type="submit" class="btn btn-primary">Search</button>
    </form>

    <hr>

    <h2>Results:</h2>
    <table class="table table-striped">
        <thead>
        <tr>
            <th>ID</th>
            <th>Title</th>
            <th>Content</th>
            <th>Age</th>
            <th>Date</th>
            <th>Status</th>
            <th>Tags</th>
            <th>Username</th>
        </tr>
        </thead>
        <tbody>
        <tr th:each="document : ${results}">
            <td th:text="${document.id}"></td>
            <td th:text="${document.title}"></td>
            <td th:text="${document.content}"></td>
            <td th:text="${document.age}"></td>
            <td th:text="${document.date}"></td>
            <td th:text="${document.status}"></td>
            <td th:text="${#strings.arrayJoin(document.tags, ', ')}"></td>
            <td th:text="${document.username}"></td>
        </tr>
        </tbody>
    </table>
</div>
</body>
</html>

8. 启动类

创建启动类 SpringBootElasticsearchDemoApplication.java

java

java 复制代码
package com.example;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class SpringBootElasticsearchDemoApplication {
    public static void main(String[] args) {
        SpringApplication.run(SpringBootElasticsearchDemoApplication.class, args);
    }
}

9. 测试数据

确保 Elasticsearch 中有一些测试数据以便进行查询。你可以使用 Kibana 或 curl 命令插入一些文档到 documents 索引中。

示例文档

json

java 复制代码
POST /documents/_doc/1
{
  "title": "Introduction to Elasticsearch",
  "content": "Elasticsearch is a distributed, RESTful search and analytics engine.",
  "age": 5,
  "date": "2023-01-01",
  "status": "published",
  "tags": ["elasticsearch", "search"],
  "username": "john_doe"
}

POST /documents/_doc/2
{
  "title": "Advanced Elasticsearch Techniques",
  "content": "Learn advanced techniques in Elasticsearch for better performance.",
  "age": 3,
  "date": "2023-06-15",
  "status": "draft",
  "tags": ["elasticsearch", "advanced"],
  "username": "jane_smith"
}

10. 运行项目

  1. 启动 Elasticsearch:确保 Elasticsearch 服务器正在运行。
  2. 插入测试数据:使用上述示例文档插入测试数据。
  3. 启动 Spring Boot 应用

bash

bash 复制代码
./mvnw spring-boot:run

4.访问应用 :打开浏览器,访问 http://localhost:8080/search

使用说明

在前端页面中,可以选择不同的查询类型并输入相应的参数,点击"Search"按钮即可查看查询结果。以下是每种查询类型的示例参数:

  • Match Query

    • Query Type: match
    • Field: content
    • Query: introduction
  • Term Query

    • Query Type: term
    • Field: status
    • Value: published
  • Terms Query

    • Query Type: terms
    • Field: tags
    • Values: elasticsearch,search
  • Range Query

    • Query Type: range
    • Field: age
    • GTE: 1
    • LTE: 5
  • Bool Query

    • Query Type: bool
    • Field: status
    • Query: published
  • Wildcard Query

    • Query Type: wildcard
    • Field: username
    • Value: john*
  • Fuzzy Query

    • Query Type: fuzzy
    • Field: username
    • Value: jon_doe
  • Match Phrase Query

    • Query Type: match_phrase
    • Field: title
    • Query: Introduction to Elasticsearch

通过这种方式,你可以在 Web 前端展示和测试八种常见的 Elasticsearch 查询类型。

相关推荐
Code_Geo几秒前
JAVA大数据场景使用StreamingOutput
java·大数据·开发语言·streamingoutput
音符犹如代码5 分钟前
Kafka 技术架构与核心原理深度解析
大数据·微服务·架构·kafka
璞华Purvar6 分钟前
璞华易知ChatBI精彩亮相百度智能云Agent大会,以自然语言驱动企业智能决策
大数据·人工智能
啊吧怪不啊吧32 分钟前
从数据到智能体大模型——cozeAI大模型开发(第二篇)
大数据·ai·语言模型·ai编程
Haooog40 分钟前
Elasticsearch (ES) 面试题清单(不定时更新)
大数据·elasticsearch·搜索引擎·面试
编织幻境的妖44 分钟前
Hadoop核心组件及其作用概述
大数据·hadoop·分布式
emfuture1 小时前
传统劳动密集型加工厂,面对日益普及的自动化技术,应如何实现转型升级?
大数据·人工智能·智能制造·工业互联网
云老大TG:@yunlaoda3601 小时前
腾讯云国际站代理商 ACE有什么优势呢?
大数据·云计算·腾讯云
百胜软件@百胜软件3 小时前
重塑零售未来:百胜智能中台+胜券AI,赋能品牌零售撬动3100亿增量市场
大数据·人工智能·零售
小辉懂编程3 小时前
Spark sql 常用时间函数 to_date ,datediff
大数据·sql·spark