Elasticsearch實戰篇——Spring Boot整合ElasticSearch
當前Spring Boot很是流行,包括我自己,也是在用Spring Boot整合其他框架進行專案開發,所以這一節,我們一起來探討Spring Boot整合ElasticSearch的問題。
本文主要講以下內容:
第一部分,通讀文件
第二部分,Spring Boot整合ElasticSearch
第三部分,基本的CRUD操作
第四部分,搜尋
第五部分,例子
還沒有學過Elasticsearch的朋友,可以先學這個系列的第一節(這個系列共三節),如果你有不明白或者不正確的地方,可以給我評論、留言或者私信。
第一步,通讀文件
Spring Data Elasticsearch 官方文件,這是當前最新的文件。
關於repository
文件一開始就介紹 CrudRepository
,比如,繼承 Repository
,其他比如 JpaRepository
、MongoRepository
是繼承CrudRepository
。也對其中的方法做了簡單說明,我們一起來看一下:
public interface CrudRepository<T, ID extends Serializable> extends Repository<T, ID> { // Saves the given entity. <S extends T> S save(S entity); // Returns the entity identified by the given ID. Optional<T> findById(ID primaryKey); // Returns all entities. Iterable<T> findAll(); // Returns the number of entities. long count(); // Deletes the given entity. void delete(T entity); // Indicates whether an entity with the given ID exists. boolean existsById(ID primaryKey); // … more functionality omitted. }
好了,下面我們看一下今天的主角 ElasticsearchRepository
他是怎樣的吧。
這說明什麼?
-
用法和JPA一樣;
-
再這他除了有CRUD的基本功能之外,還有分頁和排序。
清楚了這之後,是不是應該考慮該如何使用了呢?
如何用?
沒錯,接下來,開始說如何用,也寫了很多示例程式碼。相對來說,還是比較簡單,這裡就貼一下程式碼就行了吧。
interface PersonRepository extends Repository<User, Long> { List<Person> findByEmailAddressAndLastname(EmailAddress emailAddress, String lastname); // Enables the distinct flag for the query List<Person> findDistinctPeopleByLastnameOrFirstname(String lastname, String firstname); List<Person> findPeopleDistinctByLastnameOrFirstname(String lastname, String firstname); // Enabling ignoring case for an individual property List<Person> findByLastnameIgnoreCase(String lastname); // Enabling ignoring case for all suitable properties List<Person> findByLastnameAndFirstnameAllIgnoreCase(String lastname, String firstname); // Enabling static ORDER BY for a query List<Person> findByLastnameOrderByFirstnameAsc(String lastname); List<Person> findByLastnameOrderByFirstnameDesc(String lastname); }
是不是這樣,就可以正常使用了呢?
問題
當然可以,但是如果錯了問題怎麼辦呢,官網寫了一個常見的問題,比如包掃描問題,沒有你要的方法。
interface HumanRepository {
void someHumanMethod(User user);
}
class HumanRepositoryImpl implements HumanRepository {
public void someHumanMethod(User user) {
// Your custom implementation
}
}
interface ContactRepository {
void someContactMethod(User user);
User anotherContactMethod(User user);
}
class ContactRepositoryImpl implements ContactRepository {
public void someContactMethod(User user) {
// Your custom implementation
}
public User anotherContactMethod(User user) {
// Your custom implementation
}
}
你也可以自己寫介面,並且去實現它。
說完理論,作為我,應該在實際的程式碼中如何運用呢?
示例
官方也提供了很多示例程式碼,我們一起來看看。
@Controller
class PersonController {
@Autowired PersonRepository repository;
@RequestMapping(value = "/persons", method = RequestMethod.GET)
HttpEntity<PagedResources<Person>> persons(Pageable pageable,
PagedResourcesAssembler assembler) {
Page<Person> persons = repository.findAll(pageable);
return new ResponseEntity<>(assembler.toResources(persons), HttpStatus.OK);
}
}
這段程式碼相對來說還是十分經典的,我相信很多人都看到別人的程式碼,可能都會問,它為什麼會這麼用呢,答案或許就在這裡吧。
當然,這是以前的程式碼,或許現在用不一定合適。
高階搜尋
終於到高潮了!
學完我的第一節,你應該已經發現了,Elasticsearch搜尋是一件十分複雜的事,為了用好它,我們不得不學好它。一起加油。
到這裡,官方文件我們算是過了一遍了,大致明白了,他要告訴我們什麼。其實,文件還有很多內容,可能你遇到的問題都能在裡面找到答案。
最後,我們繼續看一下官網寫的一段處理得十分優秀的一段程式碼吧:
SearchQuery searchQuery = new NativeSearchQueryBuilder()
.withQuery(matchAllQuery())
.withIndices(INDEX_NAME)
.withTypes(TYPE_NAME)
.withFields("message")
.withPageable(PageRequest.of(0, 10))
.build();
CloseableIterator<SampleEntity> stream = elasticsearchTemplate.stream(searchQuery, SampleEntity.class);
List<SampleEntity> sampleEntities = new ArrayList<>();
while (stream.hasNext()) {
sampleEntities.add(stream.next());
}
第二部分,Spring Boot整合ElasticSearch
新增依賴
implementation 'org.springframework.boot:spring-boot-starter-data-elasticsearch'
新增配置
spring:
data:
elasticsearch:
cluster-nodes: localhost:9300
cluster-name: es-wyf
這樣就完成了整合,接下來我們用兩種方式操作。
Model
我們先寫一個的實體類,藉助這個實體類呢來完成基礎的CRUD功能。
@Data
@Accessors(chain = true)
@Document(indexName = "blog", type = "java")
public class BlogModel implements Serializable {
private static final long serialVersionUID = 6320548148250372657L;
@Id
private String id;
private String title;
//@Field(type = FieldType.Date, format = DateFormat.basic_date)
@DateTimeFormat(pattern = "yyyy-MM-dd")
@JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8")
private Date time;
}
注意id欄位是必須的,可以不寫註解@Id。
BlogRepository
public interface BlogRepository extends ElasticsearchRepository<BlogModel, String> {
}
第三部分,CRUD
基礎操作的程式碼,都是在 BlogController
裡面寫。
@RestController
@RequestMapping("/blog")
public class BlogController {
@Autowired
private BlogRepository blogRepository;
}
新增
@PostMapping("/add")
public Result add(@RequestBody BlogModel blogModel) {
blogRepository.save(blogModel);
return Result.success();
}
我們新增一條資料,標題是:Elasticsearch實戰篇:Spring Boot整合ElasticSearch,時間是:2019-03-06。我們來測試,看一下成不成功。
POST http://localhost:8080/blog/add
{
"title":"Elasticsearch實戰篇:Spring Boot整合ElasticSearch",
"time":"2019-05-06"
}
得到響應:
{
"code": 0,
"msg": "Success"
}
嘿,成功了。那接下來,我們一下查詢方法測試一下。
查詢
- 根據ID查詢
@GetMapping("/get/{id}")
public Result getById(@PathVariable String id) {
if (StringUtils.isEmpty(id))
return Result.error();
Optional<BlogModel> blogModelOptional = blogRepository.findById(id);
if (blogModelOptional.isPresent()) {
BlogModel blogModel = blogModelOptional.get();
return Result.success(blogModel);
}
return Result.error();
}
測試一下:
ok,沒問題。
- 查詢所有
@GetMapping("/get")
public Result getAll() {
Iterable<BlogModel> iterable = blogRepository.findAll();
List<BlogModel> list = new ArrayList<>();
iterable.forEach(list::add);
return Result.success(list);
}
測試一下:
GET http://localhost:8080/blog/get
結果:
{
"code": 0,
"msg": "Success",
"data": [
{
"id": "fFXTTmkBTzBv3AXCweFS",
"title": "Elasticsearch實戰篇:Spring Boot整合ElasticSearch",
"time": "2019-05-06"
}
]
}
根據ID修改
@PostMapping("/update")
public Result updateById(@RequestBody BlogModel blogModel) {
String id = blogModel.getId();
if (StringUtils.isEmpty(id))
return Result.error();
blogRepository.save(blogModel);
return Result.success();
}
測試:
POST http://localhost:8080/blog/update
{
"id":"fFXTTmkBTzBv3AXCweFS",
"title":"Elasticsearch入門篇",
"time":"2019-05-01"
}
響應:
{
"code": 0,
"msg": "Success"
}
查詢一下:
ok,成功!
刪除
- 根據ID刪除
@DeleteMapping("/delete/{id}")
public Result deleteById(@PathVariable String id) {
if (StringUtils.isEmpty(id))
return Result.error();
blogRepository.deleteById(id);
return Result.success();
}
測試:
DELETE http://localhost:8080/blog/delete/fFXTTmkBTzBv3AXCweFS
響應:
{
"code": 0,
"msg": "Success"
}
我們再查一下:
- 刪除所有資料
@DeleteMapping("/delete")
public Result deleteById() {
blogRepository.deleteAll();
return Result.success();
}
第四部分,搜尋
構造資料
為了方便測試,我們先構造資料
Repository查詢操作
搜尋標題中的關鍵字
BlogRepository
List<BlogModel> findByTitleLike(String keyword);
BlogController
@GetMapping("/rep/search/title")
public Result repSearchTitle(String keyword) {
if (StringUtils.isEmpty(keyword))
return Result.error();
return Result.success(blogRepository.findByTitleLike(keyword));
}
我們來測試一下。
POST http://localhost:8080/blog/rep/search/title?keyword=java
結果:
{
"code": 0,
"msg": "Success",
"data": [
{
"id": "f1XrTmkBTzBv3AXCeeFA",
"title": "java實戰",
"time": "2018-03-01"
},
{
"id": "fVXrTmkBTzBv3AXCHuGH",
"title": "java入門",
"time": "2018-01-01"
},
{
"id": "flXrTmkBTzBv3AXCUOHj",
"title": "java基礎",
"time": "2018-02-01"
},
{
"id": "gFXrTmkBTzBv3AXCn-Eb",
"title": "java web",
"time": "2018-04-01"
},
{
"id": "gVXrTmkBTzBv3AXCzuGh",
"title": "java ee",
"time": "2018-04-10"
}
]
}
繼續搜尋:
GET http://localhost:8080/blog/rep/search/title?keyword=入門
結果:
{
"code": 0,
"msg": "Success",
"data": [
{
"id": "hFXsTmkBTzBv3AXCtOE6",
"title": "Elasticsearch入門",
"time": "2019-01-20"
},
{
"id": "fVXrTmkBTzBv3AXCHuGH",
"title": "java入門",
"time": "2018-01-01"
},
{
"id": "glXsTmkBTzBv3AXCBeH_",
"title": "php入門",
"time": "2018-05-10"
}
]
}
為了驗證,我們再換一個關鍵字搜尋:
GET http://localhost:8080/blog/rep/search/title?keyword=java入門
{
"code": 0,
"msg": "Success",
"data": [
{
"id": "fVXrTmkBTzBv3AXCHuGH",
"title": "java入門",
"time": "2018-01-01"
},
{
"id": "hFXsTmkBTzBv3AXCtOE6",
"title": "Elasticsearch入門",
"time": "2019-01-20"
},
{
"id": "glXsTmkBTzBv3AXCBeH_",
"title": "php入門",
"time": "2018-05-10"
},
{
"id": "gFXrTmkBTzBv3AXCn-Eb",
"title": "java web",
"time": "2018-04-01"
},
{
"id": "gVXrTmkBTzBv3AXCzuGh",
"title": "java ee",
"time": "2018-04-10"
},
{
"id": "f1XrTmkBTzBv3AXCeeFA",
"title": "java實戰",
"time": "2018-03-01"
},
{
"id": "flXrTmkBTzBv3AXCUOHj",
"title": "java基礎",
"time": "2018-02-01"
}
]
}
哈哈,有沒有覺得很眼熟。
那根據上次的經驗,我們正好換一種方式解決這個問題。
@Query("{\"match_phrase\":{\"title\":\"?0\"}}")
List<BlogModel> findByTitleCustom(String keyword);
值得一提的是,官方文件示例程式碼可能是為了好看,出現問題。
官網文件給的錯誤示例:
官網示例程式碼:
另外,?0
代指變數的意思。
@GetMapping("/rep/search/title/custom")
public Result repSearchTitleCustom(String keyword) {
if (StringUtils.isEmpty(keyword))
return Result.error();
return Result.success(blogRepository.findByTitleCustom(keyword));
}
測試一下:
ok,沒有問題。
ElasticsearchTemplate
@Autowired
private ElasticsearchTemplate elasticsearchTemplate;
@GetMapping("/search/title")
public Result searchTitle(String keyword) {
if (StringUtils.isEmpty(keyword))
return Result.error();
SearchQuery searchQuery = new NativeSearchQueryBuilder()
.withQuery(queryStringQuery(keyword))
.build();
List<BlogModel> list = elasticsearchTemplate.queryForList(searchQuery, BlogModel.class);
return Result.success(list);
}
測試:
POST http://localhost:8080/blog/search/title?keyword=java入門
結果:
{
"code": 0,
"msg": "Success",
"data": [
{
"id": "fVXrTmkBTzBv3AXCHuGH",
"title": "java入門",
"time": "2018-01-01"
},
{
"id": "hFXsTmkBTzBv3AXCtOE6",
"title": "Elasticsearch入門",
"time": "2019-01-20"
},
{
"id": "glXsTmkBTzBv3AXCBeH_",
"title": "php入門",
"time": "2018-05-10"
},
{
"id": "gFXrTmkBTzBv3AXCn-Eb",
"title": "java web",
"time": "2018-04-01"
},
{
"id": "gVXrTmkBTzBv3AXCzuGh",
"title": "java ee",
"time": "2018-04-10"
},
{
"id": "f1XrTmkBTzBv3AXCeeFA",
"title": "java實戰",
"time": "2018-03-01"
},
{
"id": "flXrTmkBTzBv3AXCUOHj",
"title": "java基礎",
"time": "2018-02-01"
}
]
}
OK,暫時先到這裡,關於搜尋,我們後面會專門開一個專題,學習搜尋。
第五部分,例子
我們寫個什麼例子,想了很久,那就寫一個搜尋手機的例子吧!
介面截圖
我們先看下最後實現的效果吧
主頁效果:
分頁效果:
我們搜尋 “小米”:
我們搜尋 “1999”:
我們搜尋 “黑色”:
高階搜尋頁面:
我們使用高階搜尋,搜尋:“小米”、“1999”:
高階搜尋 “小米”、“1999” 結果:
上面的並且關係生效了嗎?我們試一下搜尋 “華為”,“1999”:
最後,我們嘗試搜尋時間段:
看一下,搜尋結果吧:
說實話,這個時間搜尋結果,我不是很滿意,ES 的時間問題,我打算在後面花一些時間去研究下。
搭建專案
基於Gradle搭建Spring Boot專案,把我折騰的受不了(如果哪位這方面有經驗,可以給我指點指點),這個demo寫了很久,那天都跑的好好的,今早上起來,就跑步起來了,一氣之下,就改成Maven了。
下面看一下我的依賴和配置
pom.xml 片段
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.3.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<repositories>
<repository>
<id>jitpack.io</id>
<url>https://jitpack.io</url>
</repository>
</repositories>
<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-web</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!--
新增 JavaLib 支援
用於介面返回
-->
<dependency>
<groupId>com.github.fengwenyi</groupId>
<artifactId>JavaLib</artifactId>
<version>1.0.7.RELEASE</version>
</dependency>
<!--
新增 webflux 支援
用於編寫非阻塞介面
-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
<!--
新增 fastjson 的支援
用於處理JSON格式資料
-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.56</version>
</dependency>
<!--
新增 Httpclient 的支援
用於網路請求
-->
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.7</version>
</dependency>
<!--
新增 jsoup 的支援
用於解析網頁內容
-->
<dependency>
<groupId>org.jsoup</groupId>
<artifactId>jsoup</artifactId>
<version>1.10.2</version>
</dependency>
</dependencies>
application.yml
server:
port: 9090
spring:
data:
elasticsearch:
cluster-nodes: localhost:9300
cluster-name: es-wyf
repositories:
enabled: true
PhoneModel
@Data
@Accessors(chain = true)
@Document(indexName = "springboot_elasticsearch_example_phone", type = "com.fengwenyi.springbootelasticsearchexamplephone.model.PhoneModel")
public class PhoneModel implements Serializable {
private static final long serialVersionUID = -5087658155687251393L;
/* ID */
@Id
private String id;
/* 名稱 */
private String name;
/* 顏色,用英文分號(;)分隔 */
private String colors;
/* 賣點,用英文分號(;)分隔 */
private String sellingPoints;
/* 價格 */
private String price;
/* 產量 */
private Long yield;
/* 銷售量 */
private Long sale;
/* 上市時間 */
//@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date marketTime;
/* 資料抓取時間 */
//@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date createTime;
}
PhoneRepository
public interface PhoneRepository extends ElasticsearchRepository<PhoneModel, String> {
}
PhoneController
@RestController
@RequestMapping(value = "/phone")
@CrossOrigin
public class PhoneController {
@Autowired
private ElasticsearchTemplate elasticsearchTemplate;
}
後面介面,都會在這裡寫。
構造資料
我的資料是抓的 “華為” 和 “小米” 官網
首先使用 httpclient
下載html,然後使用 jsoup
進行解析。
以 華為 為例:
private void huawei() throws IOException {
CloseableHttpClient httpclient = HttpClients.createDefault(); // 建立httpclient例項
HttpGet httpget = new HttpGet("https://consumer.huawei.com/cn/phones/?ic_medium=hwdc&ic_source=corp_header_consumer"); // 建立httpget例項
CloseableHttpResponse response = httpclient.execute(httpget); // 執行get請求
HttpEntity entity=response.getEntity(); // 獲取返回實體
//System.out.println("網頁內容:"+ EntityUtils.toString(entity, "utf-8")); // 指定編碼列印網頁內容
String content = EntityUtils.toString(entity, "utf-8");
response.close(); // 關閉流和釋放系統資源
// System.out.println(content);
Document document = Jsoup.parse(content);
Elements elements = document.select("#content-v3-plp #pagehidedata .plphidedata");
for (Element element : elements) {
// System.out.println(element.text());
String jsonStr = element.text();
List<HuaWeiPhoneBean> list = JSON.parseArray(jsonStr, HuaWeiPhoneBean.class);
for (HuaWeiPhoneBean bean : list) {
String productName = bean.getProductName();
List<ColorModeBean> colorsItemModeList = bean.getColorsItemMode();
StringBuilder colors = new StringBuilder();
for (ColorModeBean colorModeBean : colorsItemModeList) {
String colorName = colorModeBean.getColorName();
colors.append(colorName).append(";");
}
List<String> sellingPointList = bean.getSellingPoints();
StringBuilder sellingPoints = new StringBuilder();
for (String sellingPoint : sellingPointList) {
sellingPoints.append(sellingPoint).append(";");
}
// System.out.println("產品名:" + productName);
// System.out.println("顏 色:" + color);
// System.out.println("買 點:" + sellingPoint);
// System.out.println("-----------------------------------");
PhoneModel phoneModel = new PhoneModel()
.setName(productName)
.setColors(colors.substring(0, colors.length() - 1))
.setSellingPoints(sellingPoints.substring(0, sellingPoints.length() - 1))
.setCreateTime(new Date());
phoneRepository.save(phoneModel);
}
}
}
全文搜尋
全文搜尋來說,還是相對來說,比較簡單,直接貼程式碼吧:
/**
* 全文搜尋
* @param keyword 關鍵字
* @param page 當前頁,從0開始
* @param size 每頁大小
* @return {@link Result} 接收到的資料格式為json
*/
@GetMapping("/full")
public Mono<Result> full(String keyword, int page, int size) {
// System.out.println(new Date() + " => " + keyword);
// 校驗引數
if (StringUtils.isEmpty(page))
page = 0; // if page is null, page = 0
if (StringUtils.isEmpty(size))
size = 10; // if size is null, size default 10
// 構造分頁類
Pageable pageable = PageRequest.of(page, size);
// 構造查詢 NativeSearchQueryBuilder
NativeSearchQueryBuilder searchQueryBuilder = new NativeSearchQueryBuilder()
.withPageable(pageable)
;
if (!StringUtils.isEmpty(keyword)) {
// keyword must not null
searchQueryBuilder.withQuery(QueryBuilders.queryStringQuery(keyword));
}
/*
SearchQuery
這個很關鍵,這是搜尋條件的入口,
elasticsearchTemplate 會 使用它 進行搜尋
*/
SearchQuery searchQuery = searchQueryBuilder.build();
// page search
Page<PhoneModel> phoneModelPage = elasticsearchTemplate.queryForPage(searchQuery, PhoneModel.class);
// return
return Mono.just(Result.success(phoneModelPage));
}
官網文件也是這麼用的,所以相對來說,這還是很簡單的,不過拆詞 和 搜尋策略 搜尋速度 可能在實際使用中要考慮。
高階搜尋
先看程式碼,後面我們再來分析:
/**
* 高階搜尋,根據欄位進行搜尋
* @param name 名稱
* @param color 顏色
* @param sellingPoint 賣點
* @param price 價格
* @param start 開始時間(格式:yyyy-MM-dd HH:mm:ss)
* @param end 結束時間(格式:yyyy-MM-dd HH:mm:ss)
* @param page 當前頁,從0開始
* @param size 每頁大小
* @return {@link Result}
*/
@GetMapping("/_search")
public Mono<Result> search(String name, String color, String sellingPoint, String price, String start, String end, int page, int size) {
// 校驗引數
if (StringUtils.isEmpty(page) || page < 0)
page = 0; // if page is null, page = 0
if (StringUtils.isEmpty(size) || size < 0)
size = 10; // if size is null, size default 10
// 構造分頁物件
Pageable pageable = PageRequest.of(page, size);
// BoolQueryBuilder (Elasticsearch Query)
BoolQueryBuilder boolQueryBuilder = new BoolQueryBuilder();
if (!StringUtils.isEmpty(name)) {
boolQueryBuilder.must(QueryBuilders.matchQuery("name", name));
}
if (!StringUtils.isEmpty(color)) {
boolQueryBuilder.must(QueryBuilders.matchQuery("colors", color));
}
if (!StringUtils.isEmpty(color)) {
boolQueryBuilder.must(QueryBuilders.matchQuery("sellingPoints", sellingPoint));
}
if (!StringUtils.isEmpty(price)) {
boolQueryBuilder.must(QueryBuilders.matchQuery("price", price));
}
if (!StringUtils.isEmpty(start)) {
Date startTime = null;
try {
startTime = DateTimeUtil.stringToDate(start, DateTimeFormat.yyyy_MM_dd_HH_mm_ss);
} catch (ParseException e) {
e.printStackTrace();
}
boolQueryBuilder.must(QueryBuilders.rangeQuery("createTime").gt(startTime.getTime()));
}
if (!StringUtils.isEmpty(end)) {
Date endTime = null;
try {
endTime = DateTimeUtil.stringToDate(end, DateTimeFormat.yyyy_MM_dd_HH_mm_ss);
} catch (ParseException e) {
e.printStackTrace();
}
boolQueryBuilder.must(QueryBuilders.rangeQuery("createTime").lt(endTime.getTime()));
}
// BoolQueryBuilder (Spring Query)
SearchQuery searchQuery = new NativeSearchQueryBuilder()
.withPageable(pageable)
.withQuery(boolQueryBuilder)
.build()
;
// page search
Page<PhoneModel> phoneModelPage = elasticsearchTemplate.queryForPage(searchQuery, PhoneModel.class);
// return
return Mono.just(Result.success(phoneModelPage));
}
不管spring如何封裝,查詢方式都一樣,如下圖:
好吧,我們懷著這樣的心態去看下原始碼。
org.springframework.data.elasticsearch.core.query.SearchQuery
這個是我們搜尋需要用到物件
public NativeSearchQueryBuilder withQuery(QueryBuilder queryBuilder) {
this.queryBuilder = queryBuilder;
return this;
}
OK,根據原始碼,我們需要構造這個 QueryBuilder,那麼問題來了,這個是個什麼東西,我們要如何構造,繼續看:
org.elasticsearch.index.query.QueryBuilder
注意包名。
啥,怎麼又跑到 elasticsearch。
你想啊,你寫的東西,會讓別人直接操作嗎?
答案是不會的,我們只會提供API,所有,不管Spring如何封裝,也只會通過API去呼叫。
好吧,今天先到這裡,下一個專題,我們再討論關於搜尋問題。
連結
ElasticSearch 學習系列
程式碼
Spring Boot結合Elasticsearch,實現手機資訊搜尋小例子
演示視訊
<iframe height=498 width=510 src='http://player.youku.com/embed/XNDEwNzg4NzMwOA==' frameborder=0 'allowfullscreen'></iframe>
如果無法播放,請點選
開發十年,就只剩下這套架構體系了!
>>>
mapper sql thp 項目 分詞 tail sort com eth 前面我們已經介紹了spring boot整合Elasticsearch的jpa方式,這種方式雖然簡便,但是依舊無法解決我們較為復雜的業務,所以原生的實現方式學習能夠解決這些問題,而原生的學習方式也 最近有讀者問我能不能寫下如何使用 Spring Boot 開發 Elasticsearch(以下簡稱 ES) 相關應用,今天就講解下如何使用 Spring Boot 結合 ES。
可以在 ES 官方文件中發現,ES 為 Java REST Client 提供了兩種方式的 Client:`Java Low search 小寫 業務 jpg 啟動會 last cti cal agen 摘要: 原創出處 www.bysocket.com 「泥瓦匠BYSocket 」歡迎轉載,保留摘要,謝謝!
『 預見未來最好的方式就是親手創造未來 – 《史蒂夫·喬布斯
引入依賴
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</art
java操作elasticsearch是作為一個無資料節點與其他節點之間通訊,因此使用的是tcp埠,elasticsearch預設的節點間通訊的tcp埠是9300。elasticsearch和jdk版本一定要適配,因為elasticsearch是用java編寫的,隨著版本的升
spring boot整合elasticsearch,
啟動報錯:
Caused by: java.lang.IllegalStateException: availableProcessors is already set to [8], rejecting [8]
at
目錄
專案環境:
jdk 1.8
spring boot 1.5.1
由於spring boot 目前SpringBoot 1.5.1.RELEASE和Spring Data Elasticsearch 2.10.RELEASE僅支援Ela
1.依賴<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-elasticsearch& 基於Spring Boot自動配置的思想封裝起來,使其他Spring Boot專案引入後能夠進行快速配置。AutoConfiguration
Spring Boot的一個重要特性就是提供了各種各樣的AutoConfiguration。例如DataSourceAutoConfiguration。這樣我們只需要在
一、配置config服務端
新建配置服務專案,如config-server。
1. 在config-server專案中新增依賴
<dependencyManagement>
<dependencies>
<
Spring Boot 2.0.4 整合 swagger 2.9.2。
專案原始碼地址
一、簡介
Swagger是一款Restful介面的文件線上自動生成的軟體,也能進行功能測試。
二、使用方法
先看下目錄結構
~/workspace/gitee/high-c
首先來看官網給的版本要求:
紅框這欄指的是:Elasticsearch安裝版本(windows安裝版本或Linux按照版本)
最新因為專案需要elasticsearch,採用今天搞了好久,專案啟動就報如下錯誤:
org.elasticsearch.transport col ext sch host sca pre can -s xsd
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/ 整合 com 字段 apach param pack image ice rac 引入依賴
1:在pom文件引入mybatis-spring-boot-starter的依賴:
1 <dependency>
2 <groupId> 最近在使用Spring Boot,發現其功能真是強大,可以快速的整合很多的元件功能,非常方便:
今天就來介紹下,如何整合Redis。
定義
Redis 是一個高效能的key-value資料庫。它支援儲存的value型別很多,包括string(字串)、list(連結串列)、set(集合)、zset
一 新建pom
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId&g
1.spring boot整合redis,此次專案有進行maven的相關配置工作,整個程式碼結構目錄如下:
其中pom檔案繫結相關的redis的引數步驟如下:
其中<dependency>依賴當中進新配置了相關的redis依賴,也就是spring-boot-start
1.使用IDEA進行debug,然後進行資料的跟蹤。
根據debug的前端傳過來的資料流如下;
根據deug斷點除錯可知此時應該進入的是serviceimpl層的邏輯層程式碼。打斷點進入pipeCabinServeice的updatePipeCabin方法。
找到實現類所對應
瞭解了ES的使用場景,ES的研究、使用、推廣才更有價值和意義。
1、場景—:使用Elasticsearch作為主要的後端
傳統專案中,搜尋引擎是部署在成熟的資料儲存的頂部,以提供快速且相關的搜尋能力。這是因為早期的搜尋引擎不能提供耐 相關推薦
Elasticsearch實戰篇——Spring Boot整合ElasticSearch
Elasticsearch學習(3) spring boot整合Elasticsearch的原生方式
Spring Boot 整合 Elasticsearch 實戰
Spring Boot 整合 Elasticsearch,實現 function score query 權重分查詢
Spring boot 整合 Elasticsearch
spring boot整合elasticsearch並實現簡單的增刪改查
【spring boot】【elasticsearch】spring boot整合elasticsearch,啟動報錯Caused by: java.lang.IllegalStateException: availableProcessors is already set to [8], reje
spring boot 整合 elasticsearch 5.x
spring boot整合elasticsearch
程式設計實戰篇——Spring Boot 自動配置實現
高併發架構實戰(五) Spring Boot 整合 spring-cloud-config
高併發架構實戰(六) Spring Boot 整合 Swagger2
Spring Boot整合Spring Data Elasticsearch 踩坑
spring data整合elasticsearch的applicationContext.xml文件模板
SpringBoot自學教程 | 第四篇:Spring Boot整合mybatis
Spring Boot整合Redis實戰操作
Spring Boot整合MyBatis實戰
spring boot整合redis實戰
spring boot整合Angular專案實戰
轉 Elasticsearch的使用場景深入詳解(Elasticsearch實戰篇)