предисловие
существуетПредыдущийучитьсяSpringBoot, интегрирует Mybatis, Druid и PageHelper и реализует работу с несколькими источниками данных. В этой статье в основном представлены и используются самые популярные поисковые системы в настоящее время.ElastiSearch, и сSpringBootиспользоваться в комбинации.
Введение в эластичный поиск
ElasticSearchоснован наLuceneПоисковый сервер на самом деле правильныйLuceneИнкапсулировать и предоставить рабочий интерфейс REST APIElasticSearchЯвляясь высокомасштабируемой системой полнотекстового поиска и анализа с открытым исходным кодом, ее можно использовать для быстрого хранения, поиска и анализа больших данных.ElasticSearchОсновные характеристики: распределенная, высокодоступная, асинхронная запись, несколько API, ориентированная на документы.ElasticSearchОсновные концепции: близкое к реальному времени, кластер, узел (сохранение данных), индекс, сегментирование (сегментирование индекса), реплика (для сегментирования можно установить несколько реплик). Он может быстро хранить, искать и анализировать массивные данные.ElasticSearchПримеры использования: Википедия, Stack Overflow, Github и т. д.
SpringBoot интегрирует Elasticsearch
в настоящее время используетSpringBootИнтегрироватьElasticsearchПрежде, мы должны понять разницу между нимисоответствующая версияОтношение.
Spring Boot Version (x) | Spring Data Elasticsearch Version (y) | Elasticsearch Version (z) |
---|---|---|
x <= 1.3.5 | y <= 1.3.4 | z <= 1.7.2* |
x >= 1.4.x | 2.0.0 <=y < 5.0.0** | 2.0.0 <= z < 5.0.0** |
Здесь мы используемSpringBootВерсия 1.5.9,ElasticsearchВерсия 2.3.5.
использоватьSpringBootИнтегрироватьElasticsearch, обычно используютSpringDataОн инкапсулируется, а затем наследуется интерфейс уровня dao.ElasticsearchRepositoryкласс, который реализует множество методов, таких как часто используемые методы CRUD.
Использование SpringData
Прежде всего, сделайте соответствующие приготовления перед его использованием.
Конфигурация Maven выглядит следующим образом:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>1.5.9.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-elasticsearch</artifactId>
<version>1.5.9.RELEASE</version>
</dependency>
application.propertiesКонфигурация
spring.data.elasticsearch.repositories.enabled = true
spring.data.elasticsearch.cluster-nodes =127.0.0.1\:9300
Примечание. 9300 — это порт для клиента Java. 9200 — это интерфейс, поддерживающий Restful HTTP.
Больше конфигураций:
spring.data.elasticsearch.cluster-name Elasticsearch 集群名。(默认值: elasticsearch)
spring.data.elasticsearch.cluster-nodes 集群节点地址列表,用逗号分隔。如果没有指定,就启动一个客户端节点。
spring.data.elasticsearch.propertie 用来配置客户端的额外属性。
spring.data.elasticsearch.repositories.enabled 开启 Elasticsearch 仓库。(默认值:true。)
написание кода
класс сущности
@Document(indexName = "userindex", type = "user")
public class User implements Serializable{
/**
*
*/
private static final long serialVersionUID = 1L;
/** 编号 */
private Long id;
/** 姓名 */
private String name;
/** 年龄 */
private Integer age;
/** 描述 */
private String description;
/** 创建时间 */
private String createtm;
// getter和setter 略
}
использоватьSpringDataкогда его нужно установить в классе сущностейindexNameиtype, по сравнению с традиционными базами данных это эквивалентнобиблиотекаиповерхность. должен быть в курсеindexNameиtypeВсе должно быть строчными!!!
слой дао
public interface UserDao extends ElasticsearchRepository<User, Long>{
}
Слой dao здесь относительно прост, просто наследуйтеElasticsearchRepositoryЭтот класс подойдет. Основными методами являются сохранение, удаление и поиск. Среди них метод сохранения очень похож на вставку и обновление. Метод удаления в основном предназначен для удаления данных и библиотеки индексов. Что касается поиска, то это запрос, включающий в себя некоторые часто используемые запросы, такие как пагинация и вес.
Сервисный уровень
@Service
public class UserServiceImpl implements UserService {
@Autowired
private UserDao userDao;
@Override
public boolean insert(User user) {
boolean falg=false;
try{
userDao.save(user);
falg=true;
}catch(Exception e){
e.printStackTrace();
}
return falg;
}
@Override
public List<User> search(String searchContent) {
QueryStringQueryBuilder builder = new QueryStringQueryBuilder(searchContent);
System.out.println("查询的语句:"+builder);
Iterable<User> searchResult = userDao.search(builder);
Iterator<User> iterator = searchResult.iterator();
List<User> list=new ArrayList<User>();
while (iterator.hasNext()) {
list.add(iterator.next());
}
return list;
}
@Override
public List<User> searchUser(Integer pageNumber, Integer pageSize,String searchContent) {
// 分页参数
Pageable pageable = new PageRequest(pageNumber, pageSize);
QueryStringQueryBuilder builder = new QueryStringQueryBuilder(searchContent);
SearchQuery searchQuery = new NativeSearchQueryBuilder().withPageable(pageable).withQuery(builder).build();
System.out.println("查询的语句:" + searchQuery.getQuery().toString());
Page<User> searchPageResults = userDao.search(searchQuery);
return searchPageResults.getContent();
}
@Override
public List<User> searchUserByWeight(String searchContent) {
// 根据权重进行查询
FunctionScoreQueryBuilder functionScoreQueryBuilder = QueryBuilders.functionScoreQuery()
.add(QueryBuilders.boolQuery().should(QueryBuilders.matchQuery("name", searchContent)),
ScoreFunctionBuilders.weightFactorFunction(10))
.add(QueryBuilders.boolQuery().should(QueryBuilders.matchQuery("description", searchContent)),
ScoreFunctionBuilders.weightFactorFunction(100)).setMinScore(2);
System.out.println("查询的语句:" + functionScoreQueryBuilder.toString());
Iterable<User> searchResult = userDao.search(functionScoreQueryBuilder);
Iterator<User> iterator = searchResult.iterator();
List<User> list=new ArrayList<User>();
while (iterator.hasNext()) {
list.add(iterator.next());
}
return list;
}
}
Здесь я просто написал несколько методов, основным из которых является запрос. Запросы включают полнотекстовый поиск, запросы с разбивкой на страницы и взвешенные запросы. Что необходимо объяснить, так это взвешенный запрос. Чем выше взвешенная оценка, тем выше результаты запроса. Если для других данных не задана оценка, их оценка по умолчанию равна 1. Если вы не хотите запрашивать эти операторы, нужно только использоватьsetMinScoreУстановите его больше 1.
проверка кода
Вызов интерфейса для добавления данных
Добавлены данные:
POST http://localhost:8086/api/user
{"id":1,"name":"张三","age":20,"description":"张三是个Java开发工程师","createtm":"2018-4-25 11:07:42"}
{"id":2,"name":"李四","age":24,"description":"李四是个测试工程师","createtm":"1980-2-15 19:01:32"}
{"id":3,"name":"王五","age":25,"description":"王五是个运维工程师","createtm":"2016-8-21 06:11:32"}
Сделать полнотекстовый запроспросить
http://localhost:8086/api/user?searchContent=工程师
возвращение
[{"id":2,"name":"李四","age":14,"description":"李四是个测试工程师","createtm": "1980-2-15 19:01:32"},
{"id":1,"name":"张三","age":20,"description":"张三是个Java开发工程师", "createtm": "2018-4-25 11:07:42"},
{"id":3,"name":"王五","age":25,"description":"王五是个运维工程师","createtm": "2016-8-21 06:11:32"}]
Сделать запрос с разбивкой на страницыпросить
http://localhost:8086/api/user?pageNumber=0&pageSize=2&searchContent=工程师
возвращение
[{"id":2,"name":"李四","age":14,"description":"李四是个测试工程师"},{"id":1,"name":"张三","age":20,"description":"张三是个Java开发工程师"}]
Сделать запрос весапросить
http://localhost:8086/api/user2?searchContent=李四
возвращение
[{"id":2,"name":"李四","age":24,"description":"李四是个测试工程师","createtm":"1980-2-15 19:01:32"}]
Вывод, напечатанный запросом веса:
查询的语句:{{
"function_score" : {
"functions" : [ {
"filter" : {
"bool" : {
"should" : {
"match" : {
"name" : {
"query" : "李四",
"type" : "boolean"
}
}
}
}
},
"weight" : 10.0
}, {
"filter" : {
"bool" : {
"should" : {
"match" : {
"description" : {
"query" : "李四",
"type" : "boolean"
}
}
}
}
},
"weight" : 100.0
} ],
"min_score" : 2.0
}
}
Примечание. В тесте, поскольку минимальный вес setMinScore установлен равным 2, ненужные данные отображаться не будут. Если вы хотите отобразить его, вы можете удалить его в коде.
После добавления данных можно ввести в браузере: http://localhost:9200/_plugin/head/ Затем нажмите «Основной запрос», чтобы просмотреть добавленные данные. Если вы хотите выполнить запрос по оператору, вы можете вставить оператор запроса, напечатанный на консоли в программе, в интерфейс запроса для запроса!
Примечание: я установил ElasticSearch в Windows и установил головку плагина ES. Конкретные шаги по установке приведены в конце статьи.
Помимо SpringData есть и другие методы работыElasticSearchиз. например, используя роднойElasticSearchАпи, используйTransportClientреализация класса. Или используйте инкапсуляцию Spring, просто внедрите Bean-компоненты на уровень службы. Пример:
@Autowired
ElasticsearchTemplate elasticsearchTemplate;
Однако указанные выше методы имеют свои ограничения, т.ElasticSearchИзменения версии и соответствующие Java API постоянно корректируются, т.е.ElasticSearchПосле изменения версии сервера может потребоваться переписать клиентский код. Так что представьте очень полезный сторонний инструментJestClient, это правильноElasticSearchинкапсулироваться, заполнитьElasticSearchПустой интерфейс HttpRest для клиента, он применяется кElasticSearchВерсия 2.x или выше, нет необходимостиElasticSearchМеняйте код при изменении версии сервера!
JestClient
Сначала добавьте в Maven следующие зависимости:
<dependency>
<groupId>io.searchbox</groupId>
<artifactId>jest</artifactId>
<version>5.3.3</version>
</dependency>
Затем напишите соответствующий тестовый код. Комментарии в коде должны быть полными, поэтому я не буду вдаваться в подробности кода.
import java.util.ArrayList;
import java.util.List;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import com.pancm.pojo.User;
import io.searchbox.client.JestClient;
import io.searchbox.client.JestClientFactory;
import io.searchbox.client.JestResult;
import io.searchbox.client.config.HttpClientConfig;
import io.searchbox.core.Bulk;
import io.searchbox.core.BulkResult;
import io.searchbox.core.Delete;
import io.searchbox.core.DocumentResult;
import io.searchbox.core.Index;
import io.searchbox.core.Search;
import io.searchbox.indices.CreateIndex;
import io.searchbox.indices.DeleteIndex;
import io.searchbox.indices.mapping.GetMapping;
import io.searchbox.indices.mapping.PutMapping;
public class JestTest {
private static JestClient jestClient;
private static String indexName = "userindex";
// private static String indexName = "userindex2";
private static String typeName = "user";
private static String elasticIps="http://192.169.2.98:9200";
// private static String elasticIps="http://127.0.0.1:9200";
public static void main(String[] args) throws Exception {
jestClient = getJestClient();
insertBatch();
serach1();
serach2();
serach3();
jestClient.close();
}
private static JestClient getJestClient() {
JestClientFactory factory = new JestClientFactory();
factory.setHttpClientConfig(new HttpClientConfig.Builder(elasticIps).connTimeout(60000).readTimeout(60000).multiThreaded(true).build());
return factory.getObject();
}
public static void insertBatch() {
List<Object> objs = new ArrayList<Object>();
objs.add(new User(1L, "张三", 20, "张三是个Java开发工程师","2018-4-25 11:07:42"));
objs.add(new User(2L, "李四", 24, "李四是个测试工程师","1980-2-15 19:01:32"));
objs.add(new User(3L, "王五", 25, "王五是个运维工程师","2016-8-21 06:11:32"));
boolean result = false;
try {
result = insertBatch(jestClient,indexName, typeName,objs);
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("批量新增:"+result);
}
/**
* 全文搜索
*/
public static void serach1() {
String query ="工程师";
try {
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
searchSourceBuilder.query(QueryBuilders.queryStringQuery(query));
//分页设置
searchSourceBuilder.from(0).size(2);
System.out.println("全文搜索查询语句:"+searchSourceBuilder.toString());
System.out.println("全文搜索返回结果:"+search(jestClient,indexName, typeName, searchSourceBuilder.toString()));
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 精确搜索
*/
public static void serach2() {
try {
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
searchSourceBuilder.query(QueryBuilders.termQuery("age", 24));
System.out.println("精确搜索查询语句:"+searchSourceBuilder.toString());
System.out.println("精确搜索返回结果:"+search(jestClient,indexName, typeName, searchSourceBuilder.toString()));
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 区间搜索
*/
public static void serach3() {
String createtm="createtm";
String from="2016-8-21 06:11:32";
String to="2018-8-21 06:11:32";
try {
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
searchSourceBuilder.query(QueryBuilders.rangeQuery(createtm).gte(from).lte(to));
System.out.println("区间搜索语句:"+searchSourceBuilder.toString());
System.out.println("区间搜索返回结果:"+search(jestClient,indexName, typeName, searchSourceBuilder.toString()));
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 创建索引
* @param indexName
* @return
* @throws Exception
*/
public boolean createIndex(JestClient jestClient,String indexName) throws Exception {
JestResult jr = jestClient.execute(new CreateIndex.Builder(indexName).build());
return jr.isSucceeded();
}
/**
* 新增数据
* @param indexName
* @param typeName
* @param source
* @return
* @throws Exception
*/
public boolean insert(JestClient jestClient,String indexName, String typeName, String source) throws Exception {
PutMapping putMapping = new PutMapping.Builder(indexName, typeName, source).build();
JestResult jr = jestClient.execute(putMapping);
return jr.isSucceeded();
}
/**
* 查询数据
* @param indexName
* @param typeName
* @return
* @throws Exception
*/
public static String getIndexMapping(JestClient jestClient,String indexName, String typeName) throws Exception {
GetMapping getMapping = new GetMapping.Builder().addIndex(indexName).addType(typeName).build();
JestResult jr =jestClient.execute(getMapping);
return jr.getJsonString();
}
/**
* 批量新增数据
* @param indexName
* @param typeName
* @param objs
* @return
* @throws Exception
*/
public static boolean insertBatch(JestClient jestClient,String indexName, String typeName, List<Object> objs) throws Exception {
Bulk.Builder bulk = new Bulk.Builder().defaultIndex(indexName).defaultType(typeName);
for (Object obj : objs) {
Index index = new Index.Builder(obj).build();
bulk.addAction(index);
}
BulkResult br = jestClient.execute(bulk.build());
return br.isSucceeded();
}
/**
* 全文搜索
* @param indexName
* @param typeName
* @param query
* @return
* @throws Exception
*/
public static String search(JestClient jestClient,String indexName, String typeName, String query) throws Exception {
Search search = new Search.Builder(query)
.addIndex(indexName)
.addType(typeName)
.build();
JestResult jr = jestClient.execute(search);
// System.out.println("--"+jr.getJsonString());
// System.out.println("--"+jr.getSourceAsObject(User.class));
return jr.getSourceAsString();
}
/**
* 删除索引
* @param indexName
* @return
* @throws Exception
*/
public boolean delete(JestClient jestClient,String indexName) throws Exception {
JestResult jr = jestClient.execute(new DeleteIndex.Builder(indexName).build());
return jr.isSucceeded();
}
/**
* 删除数据
* @param indexName
* @param typeName
* @param id
* @return
* @throws Exception
*/
public boolean delete(JestClient jestClient,String indexName, String typeName, String id) throws Exception {
DocumentResult dr = jestClient.execute(new Delete.Builder(id).index(indexName).type(typeName).build());
return dr.isSucceeded();
}
Примечание. Перед тестированием позвольте мне объяснить, что версия ElasticSearch, установленная в локальной системе Windows, — 2.3.5, а версия ElasticSearch, установленная на сервере Linux, — 6.2.
Результаты теста
исследовать все
全文搜索查询语句:{
"from" : 0,
"size" : 2,
"query" : {
"query_string" : {
"query" : "工程师"
}
}
}
全文搜索返回结果:{"id":1,"name":"张三","age":20,"description":"张三是个Java开发工程师","createtm":"2018-4-25 11:07:42"},{"id":2,"name":"李四","age":24,"description":"李四是个测试工程师","createtm":"1980-2-15 19:01:32"}
поиск соответствия
精确搜索查询语句:{
"query" : {
"term" : {
"age" : 24
}
}
}
精确搜索返回结果:{"id":2,"name":"李四","age":24,"description":"李四是个测试工程师","createtm":"1980-2-15 19:01:32"}
поиск временного интервала
区间搜索语句:{
"query" : {
"range" : {
"createtm" : {
"from" : "2016-8-21 06:11:32",
"to" : "2018-8-21 06:11:32",
"include_lower" : true,
"include_upper" : true
}
}
}
}
区间搜索返回结果:{"id":1,"name":"张三","age":20,"description":"张三是个Java开发工程师","createtm":"2018-4-25 11:07:42"}
После добавления данных можем перейти в linuxKibanaРезультаты запроса следующие:
Примечание. Kibana — это программное обеспечение с открытым исходным кодом в ELK. Kibana может предоставить удобный веб-интерфейс для анализа журналов для Logstash и ElasticSearch, который может помочь обобщать, анализировать и искать важные журналы данных.
Результаты, возвращаемые тестами в приведенном выше коде, соответствуют нашим ожиданиям. Среди них используется только небольшая часть JestClient.Для большего использования вы можете проверить официальную документацию JestClient.
Установите ElasticSearch в Windows
1. Подготовка документов ссылка для скачивания: https://www.elastic.co/downloads Выберите соответствующую версию ElasticSearch, затем выберите ZIP-файл с суффиксом для загрузки и разархивируйте его после загрузки.
2. Запустите Elasticsearch Перейдите в каталог bin и запустите elasticsearch.bat. Затем при просмотре введите: localhost:9200 Удачное отображение интерфейса означает успех!
3. Установите плагин ES
установка головки интерфейса веб-управления
Войдите в каталог bin, откройте cmd и войдите в интерфейс dos.
входить:plugin install mobz/elasticsearch-head
Скачать
После успешной загрузки введите в браузере: http://localhost:9200/_plugin/head/
Если интерфейс отображается, установка прошла успешно!
4. Регистрационная служба Войдите в каталог bin, откройте cmd и войдите в интерфейс dos. Введите последовательно: установка service.bat запуск службы.bat После успеха введите services.msc Перейдите к интерфейсу службы службы, вы можете напрямую просмотреть текущий статус es!
разное
Адрес API официального сайта ElasticSearch: https://www.elastic.co/guide/en/elasticsearch/client/java-api/2.3/index.html
Адрес JestClientGithub: https://github.com/searchbox-io/Jest
Выкладываю проект на гитхаб. https://github.com/xuwujing/springBoot
Если он чувствует себя хорошо, я надеюсь дать звезду, кстати. Это конец этой статьи, спасибо за прочтение.
Уведомление об авторских правах: Автор: ничтожество Источник блога сада: http://www.cnblogs.com/xuwujing Источник CSDN: http://blog.csdn.net/qazwsxpcm Источник личного блога: http://www.panchengming.com Оригинальность непростая, пожалуйста, указывайте источник при перепечатке, спасибо!