时髦的”大数据”一词来自 3 Vs:数量、种类和速度。卷是指数据的大小;多样性是指不同类型的数据;和速度是指数据处理的速度。为了处理持久性大数据,NoSQL 数据库的写入和读取速度比 SQL 数据库快。但是,由于海量数据固有的多样性数据,搜索引擎需要查找信息,而无需使用强大的计算机功能,并且不需要花太多时间。在这篇文章中,我们将讨论两个最流行的搜索引擎,弹性搜索和ApacheSolr,以及Platform.sh如何同时支持这两个。

基于ApacheLucene,两个搜索引擎都是开源的,用Java编写。它们都有美丽、丰富的文档:

为了让您了解全文搜索 (FTS) 的相关性和有用性,本文为音乐创建了两个直接的应用程序,它们同时使用 Spring MVC 和 CRUD 功能(在数据库中创建、读取、更新和删除)。唯一的区别在于数据库:一个使用弹性搜索,另一个使用ApacheSolr。音乐的歌词包含大量的单词序列,全文引擎包括定义索引的能力;与在 SQL 数据库中使用通配符使用 LIKE 相比,它将更快、更高效。

弹性搜索

如上所述,弹性搜索基于 Lucene 库。它提供了一个分布式、支持多租户的全文搜索引擎,带有 HTTP Web 界面和无架构的 JSON 文档。它在Java上运行。

在 Maven 应用程序中,我们可以轻松地定义应用程序所需的依赖项。在弹性搜索应用程序中,我们需要将 ES 库和Platform.sh配置读取器设置为 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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>sh.platform.start</groupId>
    <artifactId>spring-mvc-maven-elasticsearch</artifactId>
    <version>0.0.1</version>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.5.RELEASE</version>
    </parent>

    <properties>
        <java.version>1.8</java.version>
        <elasticsearch.version>6.5.0</elasticsearch.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>
        <dependency>
            <groupId>org.elasticsearch.client</groupId>
            <artifactId>elasticsearch-rest-high-level-client</artifactId>
            <version>${elasticsearch.version}</version>
        </dependency>
        <dependency>
            <groupId>org

引导</组Id>
<工件Id>弹簧启动-开发工具</工件Id>
<可选>true</可选>
</依赖项>
<依赖性>
<groupId>org.springframework.boot</组Id>
<工件Id>弹簧启动-启动-测试</工件Id>
<范围>测试</范围>
</依赖项>
<依赖性>
<groupId>sh.平台</组Id>
<工件Id>配置</工件Id>
<版本>2.2.0</版本>
</依赖项>
</依赖项>

<build>
<最终名称>弹簧-mvc-maven-弹性搜索</最终名称>
<插件>
<插件>
<groupId>org.springframework.boot</组Id>
<工件Id>弹簧启动-母插件</工件Id>
</插件>
</插件>
</build>
</项目>

构建应用程序的第一步是音乐实体 – 由连续性线程及其标识定义的对象,而不是由其属性定义的对象。

public class Music {

    private String id;

    private String name;

    private String singer;

    private int year;

    private String lyrics;

  //getter and setter

}

核心 Spring 概念应用于解决方案开发的 Spring 数据 ES 使用弹性搜索搜索引擎。但是,它使用已弃用为 Java 高级 REST 客户端的传输客户端,并将在 ElasticSearch 8.0 上删除。因此,此应用程序使用来自弹性搜索的 Java 高级 REST 客户端。使用 Bean 注释,我们将提供将在服务层上使用的 RestHighLevelClient 实例。此配置类将创建由Platform.sh提供的 RestHighLevel 客户端。

import org.elasticsearch.action.admin.indices.create.CreateIndexRequest;
import org.elasticsearch.action.admin.indices.create.CreateIndexResponse;
import org.elasticsearch.action.admin.indices.get.GetIndexRequest;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import sh.platform.config.Config;
import sh.platform.config.Elasticsearch;

import java.io.IOException;

@Configuration
public class ElasticsearchConfig {

    static final String INDEX = "musics";
    static final String TYPE = "music";

    @Bean
    public RestHighLevelClient elasticsearchTemplate() throws IOException {
        Config config = new Config();
        final Elasticsearch credential = config.getCredential("elasticsearch", Elasticsearch::new);
        final RestHighLevelClient client = credential.get();
        CreateIndexRequest request = new CreateIndexRequest(INDEX);

        GetIndexRequest exist = new GetIndexRequest();
        exist.indices(INDEX);
        if (!client.indices().exists(exist, RequestOptions.DEFAULT)) {
            client.indices().create(request, RequestOptions.DEFAULT);
        }
        return client;
    }
}

服务层位于 entities 类的顶部,用于处理业务需求,包括具有 CRUD 操作的数据库控制以及搜索音乐中的名称、歌词和歌手字段中的字词更快xml.jackson.databind.ObjectMapper;
导入 org.弹性搜索.action.delete.删除请求;
导入 org.弹性搜索.action.get.GetRequest;
导入 org.弹性搜索.action.get.Get 响应;
导入 org.弹性搜索.action.index.索引请求;
导入 org.弹性搜索.action.search.Search 请求;
导入 org.弹性搜索.action.search.搜索响应;
导入 org.弹性搜索.客户端.请求选项;
导入 org.弹性搜索.client.RestLevel 客户端;
导入 org.弹性搜索.index.query.BoolQueryBuilder;
导入 org.弹性搜索.search.SearchHit;
导入 org.弹性搜索.search.builder.搜索来源构建器;
导入 org.springframework.be.factory.注释.自动连线;
导入组织.springframework.构造型.存储库;
进口组织.蒂梅利夫.util.StringUtils;

导入 java.io.IO 异常;
导入 java.util.list;
导入 java.util.Map;
导入 java.util.可选;
导入 java.util.UUID;
导入 java.util.stream.收发器;

导入静态 java.util.stream.stream.stream.stream.stream.stream.stream;导入静态 java.util.stream.stream.stream
导入静态 org.弹性搜索.index.query.QueryBuilders.boolQuery;
导入静态 org.弹性搜索.index.query.QueryBuilders.术语查询;
导入静态 sh.platform.模板.弹性搜索Config.INDEX;
导入静态 sh.platform.模板.弹性搜索Config.TYPE;

@Repository
公共类音乐服务 |

@Autowired
私有对象映射器对象映射器;

@Autowired
私人 RestLevel 客户端;

公共列表\lt;音乐>查找所有(字符串搜索)抛出 IO 异常 |

搜索来源构建器生成器 = 新的搜索源构建器();
如果(!斯特林Utils.isempty(搜索)) |
最终 BoolQueryBuilder 查询构建器 = boolQuery(应)应(术语查询(“歌词”,搜索))
.应(术语查询(“名称”,搜索))
.应(术语查询(“歌手”,搜索);
源构建器.查询(查询构建器);
}

搜索请求搜索请求 = 新的搜索请求();
搜索请求.索引(INDEX);
搜索请求.源(源构建器);
搜索响应 = 客户端.搜索(搜索请求、请求选项.DEFAULT);
返回流(响应.getHits()。 拆分器(),错误)
.map(搜索命中:获取来源AsMap)
.map(s > 对象映射值(s,音乐类))
.collect(收集者.tolist());
}

公共列表\lt;音乐>findAll()抛出IO异常 |
返回查找 All(空);
}

公共可选_lt;音乐>查找ById(字符串ID)抛出IO异常 |

获取请求请求 = 新的获取请求(INDEX、TYPE、ID);
最终 Get 响应响应 = 客户端.get(请求、请求选项.DEFAULT);
最终映射\lt;String,对象>源 = 响应.getSource();
如果 (源.是空)) |
返回可选.empty();
* 其他 *
返回可选的可转换(对象映射器.转换值(源,音乐.类);”
}
}

公共空白保存(音乐)抛出 IO 异常 |

如果 (StringUtils.是空 (音乐.getId()) ]
音乐.setID(UUID.随机UUID()toString());
}
映射<String,对象>jsonMap = 对象Mapper.转换值(音乐,Map.class);
索引请求索引请求 = 新索引请求(INDEX、TYPE)
.id(音乐.getId))))源(jsonMap);
客户端.索引(索引请求、请求选项.DEFAULT);
}

公共无效删除(音乐)抛出 IO 异常 |
客户端.删除(新的删除请求(INDEX、TYPE、音乐.getId())、请求选项.DEFAULT);
}
}

在 Spring 构建网站的方法中,HTTP 请求由控制器处理。您可以通过注释快速识别这些 @Controller 请求。在下面的示例中, MusicController 处理 HTTP 请求。

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.GetMapping;
import org

web.bind.注释.路径变量;
导入 org.springframework.web.bind.注释.PostMap;
导入 org.springframework.web.bind.注释.请求Param;

导入 javax.验证.valid;
导入 java.io.IO 异常;

导入静态 java.util.stream.collectors.toList;

@Controller
公共类音乐控制器 |

@Autowired
私人音乐服务音乐服务;

@GetMapping(“/”)
公共字符串开始(@RequestParam(名称 = “搜索”,必需 = false) 字符串搜索,模型模型) 引发 IOException |

模型.add属性(“音乐”,音乐服务.findAll(搜索));
模型.add属性(“搜索”,搜索);
返回”索引”;
}

@GetMapping(“/添加”)
公共字符串添加用户(模型模型) |
模型.add属性(“音乐”,新音乐());
返回”附加音乐”;
}

@PostMapping(“/添加”)
公共字符串添加用户(@Valid音乐,绑定结果结果,模型模型) 引发 IO 异常 |
如果(结果.有错误)) |
返回”附加音乐”;
}
音乐服务.保存(音乐);
模型.add属性(“音乐”,音乐服务.findAll());
返回”索引”;
}

@GetMapping(“/编辑/[id])”
公共字符串显示UpdateForm(@PathVariable(“id”)字符串ID,模型模型)引发IO异常 |
音乐与音乐服务.findById(id).orElseThrow(() ->新的非法参数异常(“无效音乐 ID:”= id));
模型.add属性(“音乐”,音乐);
返回”附加音乐”;
}

@PostMapping(“/更新/[id])
公共字符串更新用户(@PathVariable(“id”)字符串 ID,@Valid音乐,绑定结果结果,模型模型) 引发 IO异常 |
如果(结果.有错误)) |
音乐.setId(id);
返回”附加音乐”;
}

音乐服务.保存(音乐);
模型.add属性(“音乐”,音乐服务.findAll());
返回”索引”;
}

@GetMapping(“/删除/[id]”
公共字符串删除用户(@PathVariable(“id”)字符串 ID,模型模型) 引发 IO 异常 |
音乐与音乐服务.findById(id).orElseThrow(() ->新的非法参数异常(“无效音乐 ID:”= id));
音乐服务.删除(音乐);
模型.add属性(“音乐”,音乐服务.findAll()
.stream()
.筛选器(m -> .m.getId() 等于(id))
.收集(到列表));
返回”索引”;
}
}

只需一个简单的步骤即可Platform.sh上配置弹性搜索。只需将此值追加到服务文件:

elasticsearch:
    type: elasticsearch:6.5
    disk: 256
    size: S

要获取有关Platform.sh的配置文件的更多详细信息,请查看此帖子,其中介绍如何创建或移动到Platform.sh。

阿帕奇·索尔

Solr 是一个开源的企业搜索平台,以 Java 编写,是 Apache Lucene 项目的一部分。其主要功能包括全文搜索、命中突出显示、分面搜索、实时索引、动态群集、数据库集成、NoSQL 功能和昂贵的文档处理。

与弹性搜索应用程序一样,Apache Solr 示例代码需要定义一个具有其依赖项的”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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>sh

开始</组Id>
<工件Id>弹簧-mvc-maven-solr</工件Id>
<版本>0.0.1</版本>

<父>
<groupId>org.springframework.boot</组Id>
<工件Id>弹簧启动-启动-父-lt;/工件Id>
<版本>2.1.5.RELEASE</版本>
</父>

<属性>
<java.版本>1.8</java.版本>
<弹性搜索.版本>6.5.0</弹性搜索.版本>
</属性>

<依赖关系>
<依赖性>
<groupId>org.springframework.boot</组Id>
<工件Id>弹簧启动-启动-网络</工件Id>
</依赖项>
<依赖性>
<groupId>org.springframework.boot</组Id>
<工件Id>弹簧启动-启动器-百利叶</工件Id>
</依赖项>
<依赖性>
<groupId>org.springframework.data</组Id>
<工件Id>弹簧数据-索lr</工件Id>
<版本>4.0.8.RELEASE</版本>
</依赖项>

<依赖性>
<groupId>org.springframework.boot</组Id>
<工件Id>弹簧启动-开发工具</工件Id>
<可选>true</可选>
</依赖项>
<依赖性>
<groupId>org.springframework.boot</组Id>
<工件Id>弹簧启动-启动-测试</工件Id>
<范围>测试</范围>
</依赖项>
<依赖性>
<groupId>sh.平台</组Id>
<工件Id>配置</工件Id>
<版本>2.2.0</版本>
</依赖项>
</依赖项>

<build>
<最终名称>弹簧-mvc-maven-solr</最终名称>
<插件>
<插件>
<groupId>org.springframework.boot</组Id>
<工件Id>弹簧启动-母插件</工件Id>
</插件>
</插件>
</build>
</项目>

得益于支持 Apache Solr 的 Spring 数据,我们可以轻松地从 Spring 应用程序配置和访问 Apache Solr 搜索服务器。Music实体类具有注释来映射字段并执行 Java 和 Apache Solr 之间的转换过程。

import org.springframework.data.annotation.Id;
import org.springframework.data.solr.core.mapping.Indexed;
import org.springframework.data.solr.core.mapping.SolrDocument;

@SolrDocument(collection = "collection1")
public class Music {

    @Id
    @Indexed(name = "id", type = "string")
    private String id;

    @Indexed(name = "name", type = "string")
    private String name;

    @Indexed(name = "singer", type = "string")
    private String singer;

    @Indexed(name = "year", type = "string")
    private int year;

    @Indexed(name = "lyrics", type = "string")
    private String lyrics;

 //getter and setter
}

要使用 Spring Data 功能, SolrTemplate 需要 实例;这就是为什么我们具有使 Spring SolrConfig SolrTemplate 符合条件的类的原因。然后,它返回由Platform.sh生成的 Apache Solr 客户端实例。

import org.apache.solr.client.solrj.impl.HttpSolrClient;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.solr.core.SolrTemplate;
import sh.platform.config.Config;
import sh.platform.config.Solr;

@Configuration
public class SolrConfig {

    @Bean
    public HttpSolrClient elasticsearchTemplate() {
        Config config = new Config();
        final Solr credential = config

get();
字符串 URL = httpSolrClient.getBaseURL();
httpSolrClient.setBaseURL(url.substring(0,url.lastIndexOf(‘/’));
返回 httpSolr 客户端;
}

@Bean
公共 SolrTemplate solTemplate(httpSolr客户端) |
返回新的 SolrTemplate(客户端);
}
}

Spring Data 的一个神奇优势是,我们有一个存储库接口,它是与任何数据库通信的中央接口。此存储库界面允许通过 Spring Data 将查询方法功能直接交给开发人员。

import org.springframework.data.solr.repository.Query;
import org.springframework.data.solr.repository.SolrCrudRepository;

import java.util.List;

public interface MusicRepository extends SolrCrudRepository<Music, String> {

    @Query("lyrics:*?0* OR name:*?0* OR singer:*?0*")
    List<Music> search(String searchTerm);
}


import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;
import org.thymeleaf.util.StringUtils;

import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.UUID;

import static java.util.stream.Collectors.toList;
import static java.util.stream.StreamSupport.stream;

@Repository
public class MusicService {

    @Autowired
    private MusicRepository repository;

    public List<Music> findAll(String search) {

        if (repository.count() == 0) {
            return Collections.emptyList();
        }

        if (StringUtils.isEmpty(search)) {
            return stream(repository.findAll().spliterator(), false)
                    .collect(toList());
        }
        return repository.search(search);
    }

    public List<Music> findAll() {
        return findAll(null);
    }

    public Optional<Music> findById(String id) {
        return repository.findById(id);
    }

    @Transactional
    public void save(Music music) {
        if (StringUtils.isEmpty(music.getId())) {
            music.setId(UUID.randomUUID().toString());
        }
        repository.save(music);
    }


    @Transactional
    public void delete(Music music) {
        repository.delete(music);
    }
}

创建由Platform.sh提供的 Apache Solr 实例只需一个简单的步骤即可完成。只需将此值追加到服务文件:

solr:
    type: solr:7.7
    disk: 1024
    size: S
    configuration:
        cores:
            collection1:
                conf_dir: !archive "core1-conf"
        endpoints:
            solr:
                core: collection1

两个应用程序的控制器都相同,因此我们不需要复制源代码。

此外,由于 Thymeleaf 模板引擎,两者都使用相同的前端文件,如 HTML、CSS 和 JavaScript。它提供了一组 Spring 集成,使您能够在 Spring MVC 应用中将其用作 JSP 的全功能替代品。

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<html>
<head>
    <title>Music Store</title>
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link rel="stylesheet" href="/css/bootstrap.min.css">
</head>
<body>
<div class="container">
    <h1>Music Store</h1>

    <form class="form-search" method="get" action="/">
        <i class="icon-music"></i>
        <input type="text" class="input-medium search-query" name="search" >
        <button type="submit" class="btn">Search</button>
        <a href="/add" role="button" class="btn" data-toggle="modal">Add music</a>
        <table class="table table-bordered">
            <thead>
            <tr>
                <th>Music</th>
                <th>Year</th>
                <th>Singer</th>
                <th>Edit</th>
                <th>Delete</th>
            </tr>
            </thead>
            <tbody>
            <tr th:each="music : ${musics}">
                <td th:text="${music

年份\”></td>
<td th:text=”${music.singer}”></td>
<td><lt;lt;lt;lt;lt;<lt;td><<<<<<<<<<<<<<<<<<</a<<<<lt;<lt;<<<<lt;/a_lt;<<lt;<</t;<<<_t/lt;/a<<<<<<gt;<gt;<<_lt;/a_lt;_lt;\lt;/a<lt;</a1>第三;\{3;lt;\\lt;</a_
<td><lt;lt;lt;lt;lt;lt;lt;lt;td-gt;<<<<<<<<<<<<<<<<<<lt;<<<<lt;/a_lt;<lt;<<<lt;/a_lt;<<lt;<</t;<<<_t/lt;/a<<<<<<gt;<gt;<<_lt;_lt;_lt;\lt;/a<gt;lt;\/但&3;</a_lt;\\\\\但</
</tr>
</tbody>
</tbody>
</表>
</form>
</div>
<脚本 src=”https://code.jquery.com/jquery.js”></script>
<脚本 src=”/js/boottrap.min.js”></脚本>
</body>
</html>

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<html>
<head>
    <title>Music Store</title>
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link rel="stylesheet" href="/css/bootstrap.min.css">
</head>
<body>

<div class="container">
    <h1>Music Store</h1>
    <form th:action="@{/add}" th:object="${music}" method="post">
        <input id="id" name="id" type="hidden" th:field="*{id}">
        <div class="form-group">
            <label for="musicNameId">Name</label>
            <input type="text" class="form-control" th:field="*{name}" id="musicNameId" placeholder="Enter Music">
        </div>
        <div class="form-group">
            <label for="musicYearId">Year</label>
            <input type="number" class="form-control" th:field="*{year}" id="musicYearId" placeholder="Enter Year"
                   min="1000" max="2020">
        </div>
        <div class="form-group">
            <label for="musicSingerId">Singer</label>
            <input type="text" class="form-control" th:field="*{singer}" id="musicSingerId" placeholder="Enter Singer">
        </div>
        <div class="form-group">
            <label for="musicLyricsId">Lyrics</label>
            <textarea class="form-control" id="musicLyricsId" rows="3" th:field="*{lyrics}"></textarea>
        </div>
        <button type="submit" class="btn">Save</button>
    </form>
</div>
<script src="https://code.jquery.com/jquery.js"></script>
<script src="/js/bootstrap.min.js"></script>
</body>
</html>

我希望这篇文章有助于解释全文搜索引擎(而不是类SQL数据库)的好处,有两个梦幻般的示例应用程序,比较最流行的FTS之间的代码:弹性搜索和ApacheSolr。两者都是开源的,有丰富的文档,并且都支持Platform.sh!

Platform.sh使您能够非常轻松地利用弹性搜索或 Apache Solr 来满足您的业务需求。

我们还有一个包含Java代码示例的存储库,除了Java模板。敬请关注:如果您是雅加达 EE 爱好者,请留意我们即将发布的帖子!

Comments are closed.