很全很牛逼,看完这篇Elasticsearch实战,我觉得我可以写个百度~

当前Spring Boot很是流行,包括我自己,也是在用Spring Boot集成其他框架进行项目开发,所以这一节,我们一起来探讨Spring Boot整合ElasticSearch的问题。

本文主要讲以下内容:

  • 第一部分,通读文档

  • 第二部分,Spring Boot整合ElasticSearch

  • 第三部分,基本的CRUD操作

  • 第四部分,搜索

  • 第五部分,例子

还没有学过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 他是怎样的吧。

image

这说明什么?

  • 用法和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();`

  `}`

测试一下:

image

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"`

  `}`

查询一下:

image

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"`

`}`

我们再查一下:

image

  • 删除所有数据
`@DeleteMapping("/delete")`

 `public  Result deleteById()  {`

  `blogRepository.deleteAll();`

 `return  Result.success();`

  `}`

分享一套SpringBoot开发博客系统源码,以及完整开发文档!速度保存!

第四部分,搜索

构造数据

为了方便测试,我们先构造数据

image

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"`

  `},`

10.  `{`

11.  `"id":  "hFXsTmkBTzBv3AXCtOE6",`

12.  `"title":  "Elasticsearch入门",`

13.  `"time":  "2019-01-20"`

14.  `},`

15.  `{`

16.  `"id":  "glXsTmkBTzBv3AXCBeH_",`

17.  `"title":  "php入门",`

18.  `"time":  "2018-05-10"`

19.  `},`

20.  `{`

21.  `"id":  "gFXrTmkBTzBv3AXCn-Eb",`

22.  `"title":  "java web",`

23.  `"time":  "2018-04-01"`

24.  `},`

25.  `{`

26.  `"id":  "gVXrTmkBTzBv3AXCzuGh",`

27.  `"title":  "java ee",`

28.  `"time":  "2018-04-10"`

29.  `},`

30.  `{`

31.  `"id":  "f1XrTmkBTzBv3AXCeeFA",`

32.  `"title":  "java实战",`

33.  `"time":  "2018-03-01"`

34.  `},`

35.  `{`

36.  `"id":  "flXrTmkBTzBv3AXCUOHj",`

37.  `"title":  "java基础",`

38.  `"time":  "2018-02-01"`

39.  `}`

40.  `]`

41.  `}`

哈哈,有没有觉得很眼熟。

那根据上次的经验,我们正好换一种方式解决这个问题。

1.  `@Query("{\"match_phrase\":{\"title\":\"?0\"}}")`

2.  `List<BlogModel> findByTitleCustom(String keyword);`

值得一提的是,官方文档示例代码可能是为了好看,出现问题。

官网文档给的错误示例:

image

官网示例代码:

image

官方示例代码

另外, ?0 代指变量的意思。

1.  `@GetMapping("/rep/search/title/custom")`

2.  `public  Result repSearchTitleCustom(String keyword)  {`

3.  `if  (StringUtils.isEmpty(keyword))`

4.  `return  Result.error();`

5.  `return  Result.success(blogRepository.findByTitleCustom(keyword));`

6.  `}`

测试一下:

image

ok,没有问题。

ElasticsearchTemplate
1.  `@Autowired`

2.  `private  ElasticsearchTemplate elasticsearchTemplate;`

4.  `@GetMapping("/search/title")`

5.  `public  Result searchTitle(String keyword)  {`

6.  `if  (StringUtils.isEmpty(keyword))`

7.  `return  Result.error();`

8.  `SearchQuery searchQuery =  new  NativeSearchQueryBuilder()`

9.  `.withQuery(queryStringQuery(keyword))`

10.  `.build();`

11.  `List<BlogModel> list = elasticsearchTemplate.queryForList(searchQuery,  BlogModel.class);`

12.  `return  Result.success(list);`

13.  `}`

测试:

POST http://localhost:8080/blog/search/title?keyword=java入门

结果:

1.  `{`

2.  `"code":  0,`

3.  `"msg":  "Success",`

4.  `"data":  [`

5.  `{`

6.  `"id":  "fVXrTmkBTzBv3AXCHuGH",`

7.  `"title":  "java入门",`

8.  `"time":  "2018-01-01"`

9.  `},`

10.  `{`

11.  `"id":  "hFXsTmkBTzBv3AXCtOE6",`

12.  `"title":  "Elasticsearch入门",`

13.  `"time":  "2019-01-20"`

14.  `},`

15.  `{`

16.  `"id":  "glXsTmkBTzBv3AXCBeH_",`

17.  `"title":  "php入门",`

18.  `"time":  "2018-05-10"`

19.  `},`

20.  `{`

21.  `"id":  "gFXrTmkBTzBv3AXCn-Eb",`

22.  `"title":  "java web",`

23.  `"time":  "2018-04-01"`

24.  `},`

25.  `{`

26.  `"id":  "gVXrTmkBTzBv3AXCzuGh",`

27.  `"title":  "java ee",`

28.  `"time":  "2018-04-10"`

29.  `},`

30.  `{`

31.  `"id":  "f1XrTmkBTzBv3AXCeeFA",`

32.  `"title":  "java实战",`

33.  `"time":  "2018-03-01"`

34.  `},`

35.  `{`

36.  `"id":  "flXrTmkBTzBv3AXCUOHj",`

37.  `"title":  "java基础",`

38.  `"time":  "2018-02-01"`

39.  `}`

40.  `]`

41.  `}`

OK,暂时先到这里,关于搜索,我们后面会专门开一个专题,学习搜索。

分享一套SpringBoot开发博客系统源码,以及完整开发文档!速度保存!

第五部分,例子

我们写个什么例子,想了很久,那就写一个搜索手机的例子吧!

界面截图

我们先看下最后实现的效果吧

主页效果:

image

分页效果:

image

我们搜索 “小米”:

image

我们使用高级搜索,搜索:“小米”、“1999”:

image

高级搜索 “小米”、“1999” 结果:

image

上面的并且关系生效了吗?我们试一下搜索 “华为”,“1999”:

image

最后,我们尝试搜索时间段:

image

看一下,搜索结果吧:

image

说实话,这个时间搜索结果,我不是很满意,ES 的时间问题,我打算在后面花一些时间去研究下。

搭建项目

基于Gradle搭建Spring Boot项目,把我折腾的受不了(如果哪位这方面有经验,可以给我指点指点),这个demo写了很久,那天都跑的好好的,今早上起来,就跑步起来了,一气之下,就改成Maven了。

下面看一下我的依赖和配置

pom.xml 片段

1.  `<parent>`

2.  `<groupId>org.springframework.boot</groupId>`

3.  `<artifactId>spring-boot-starter-parent</artifactId>`

4.  `<version>2.1.3.RELEASE</version>`

5.  `<relativePath/>  <!-- lookup parent from repository -->`

6.  `</parent>`

8.  `<repositories>`

9.  `<repository>`

10.  `<id>jitpack.io</id>`

11.  `<url>https://jitpack.io</url>`

12.  `</repository>`

13.  `</repositories>`

15.  `<dependencies>`

16.  `<dependency>`

17.  `<groupId>org.springframework.boot</groupId>`

18.  `<artifactId>spring-boot-starter-data-elasticsearch</artifactId>`

19.  `</dependency>`

20.  `<dependency>`

21.  `<groupId>org.springframework.boot</groupId>`

22.  `<artifactId>spring-boot-starter-web</artifactId>`

23.  `</dependency>`

25.  `<dependency>`

26.  `<groupId>org.projectlombok</groupId>`

27.  `<artifactId>lombok</artifactId>`

28.  `<optional>true</optional>`

29.  `</dependency>`

30.  `<dependency>`

31.  `<groupId>org.springframework.boot</groupId>`

32.  `<artifactId>spring-boot-starter-test</artifactId>`

33.  `<scope>test</scope>`

34.  `</dependency>`

36.  `<!--`

37.  `添加 JavaLib 支持`

38.  `用于接口返回`

39.  `-->`

40.  `<dependency>`

41.  `<groupId>com.github.fengwenyi</groupId>`

42.  `<artifactId>JavaLib</artifactId>`

43.  `<version>1.0.7.RELEASE</version>`

44.  `</dependency>`

46.  `<!--`

47.  `添加 webflux 支持`

48.  `用于编写非阻塞接口`

49.  `-->`

50.  `<dependency>`

51.  `<groupId>org.springframework.boot</groupId>`

52.  `<artifactId>spring-boot-starter-webflux</artifactId>`

53.  `</dependency>`

55.  `<!--`

56.  `添加 fastjson 的支持`

57.  `用于处理JSON格式数据`

58.  `-->`

59.  `<dependency>`

60.  `<groupId>com.alibaba</groupId>`

61.  `<artifactId>fastjson</artifactId>`

62.  `<version>1.2.56</version>`

63.  `</dependency>`

65.  `<!--`

66.  `添加 Httpclient 的支持`

67.  `用于网络请求`

68.  `-->`

69.  `<dependency>`

70.  `<groupId>org.apache.httpcomponents</groupId>`

71.  `<artifactId>httpclient</artifactId>`

72.  `<version>4.5.7</version>`

73.  `</dependency>`

75.  `<!--`

76.  `添加 jsoup 的支持`

77.  `用于解析网页内容`

78.  `-->`

79.  `<dependency>`

80.  `<groupId>org.jsoup</groupId>`

81.  `<artifactId>jsoup</artifactId>`

82.  `<version>1.10.2</version>`

83.  `</dependency>`

84.  `</dependencies>`

application.yml

1.  `server:`

2.  `port:  9090`

4.  `spring:`

5.  `data:`

6.  `elasticsearch:`

7.  `cluster-nodes: localhost:9300`

8.  `cluster-name: es-wyf`

9.  `repositories:`

10.  `enabled:  true`

PhoneModel

1.  `@Data`

2.  `@Accessors(chain =  true)`

3.  `@Document(indexName =  "springboot_elasticsearch_example_phone", type =  "com.fengwenyi.springbootelasticsearchexamplephone.model.PhoneModel")`

4.  `public  class  PhoneModel  implements  Serializable  {`

5.  `private  static  final  long serialVersionUID =  -5087658155687251393L;`

7.  `/* ID */`

8.  `@Id`

9.  `private  String id;`

11.  `/* 名称 */`

12.  `private  String name;`

14.  `/* 颜色,用英文分号(;)分隔 */`

15.  `private  String colors;`

17.  `/* 卖点,用英文分号(;)分隔 */`

18.  `private  String sellingPoints;`

20.  `/* 价格 */`

21.  `private  String price;`

23.  `/* 产量 */`

24.  `private  Long  yield;`

26.  `/* 销售量 */`

27.  `private  Long sale;`

29.  `/* 上市时间 */`

30.  `//@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")`

31.  `@JsonFormat(pattern =  "yyyy-MM-dd HH:mm:ss", timezone =  "GMT+8")`

32.  `private  Date marketTime;`

34.  `/* 数据抓取时间 */`

35.  `//@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")`

36.  `@JsonFormat(pattern =  "yyyy-MM-dd HH:mm:ss", timezone =  "GMT+8")`

37.  `private  Date createTime;`

39.  `}`

PhoneRepository

1.  `public  interface  PhoneRepository  extends  ElasticsearchRepository<PhoneModel,  String>  {`

2.  `}`

PhoneController

1.  `@RestController`

2.  `@RequestMapping(value =  "/phone")`

3.  `@CrossOrigin`

4.  `public  class  PhoneController  {`

6.  `@Autowired`

7.  `private  ElasticsearchTemplate elasticsearchTemplate;`

9.  `}`

后面接口,都会在这里写。

构造数据

我的数据是抓的 “华为” 和 “小米” 官网

首先使用 httpclient 下载html,然后使用 jsoup 进行解析。

以 华为 为例:

1.  `private  void huawei()  throws  IOException  {`

2.  `CloseableHttpClient httpclient =  HttpClients.createDefault();  // 创建httpclient实例`

3.  `HttpGet httpget =  new  HttpGet("https://consumer.huawei.com/cn/phones/?ic_medium=hwdc&ic_source=corp_header_consumer");  // 创建httpget实例`

5.  `CloseableHttpResponse response = httpclient.execute(httpget);  // 执行get请求`

6.  `HttpEntity entity=response.getEntity();  // 获取返回实体`

7.  `//System.out.println("网页内容:"+ EntityUtils.toString(entity, "utf-8")); // 指定编码打印网页内容`

8.  `String content =  EntityUtils.toString(entity,  "utf-8");`

9.  `response.close();  // 关闭流和释放系统资源`

11.  `//        System.out.println(content);`

13.  `Document document =  Jsoup.parse(content);`

14.  `Elements elements = document.select("#content-v3-plp #pagehidedata .plphidedata");`

15.  `for  (Element element : elements)  {`

16.  `//            System.out.println(element.text());`

17.  `String jsonStr = element.text();`

18.  `List<HuaWeiPhoneBean> list = JSON.parseArray(jsonStr,  HuaWeiPhoneBean.class);`

19.  `for  (HuaWeiPhoneBean bean : list)  {`

20.  `String productName = bean.getProductName();`

21.  `List<ColorModeBean> colorsItemModeList = bean.getColorsItemMode();`

23.  `StringBuilder colors =  new  StringBuilder();`

24.  `for  (ColorModeBean colorModeBean : colorsItemModeList)  {`

25.  `String colorName = colorModeBean.getColorName();`

26.  `colors.append(colorName).append(";");`

27.  `}`

29.  `List<String> sellingPointList = bean.getSellingPoints();`

30.  `StringBuilder sellingPoints =  new  StringBuilder();`

31.  `for  (String sellingPoint : sellingPointList)  {`

32.  `sellingPoints.append(sellingPoint).append(";");`

33.  `}`

35.  `//                System.out.println("产品名:" + productName);`

36.  `//                System.out.println("颜  色:" + color);`

37.  `//                System.out.println("买  点:" + sellingPoint);`

38.  `//                System.out.println("-----------------------------------");`

39.  `PhoneModel phoneModel =  new  PhoneModel()`

40.  `.setName(productName)`

41.  `.setColors(colors.substring(0, colors.length()  -  1))`

42.  `.setSellingPoints(sellingPoints.substring(0, sellingPoints.length()  -  1))`

43.  `.setCreateTime(new  Date());`

44.  `phoneRepository.save(phoneModel);`

45.  `}`

46.  `}`

47.  `}`
全文搜索

全文搜索来说,还是相对来说,比较简单,直接贴代码吧:

1.  `/**`

2.  `* 全文搜索`

3.  `* @param keyword 关键字`

4.  `* @param page 当前页,从0开始`

5.  `* @param size 每页大小`

6.  `* @return {@link Result} 接收到的数据格式为json`

7.  `*/`

8.  `@GetMapping("/full")`

9.  `public  Mono<Result> full(String keyword,  int page,  int size)  {`

10.  `// System.out.println(new Date() + " => " + keyword);`

12.  `// 校验参数`

13.  `if  (StringUtils.isEmpty(page))`

14.  `page =  0;  // if page is null, page = 0`

16.  `if  (StringUtils.isEmpty(size))`

17.  `size =  10;  // if size is null, size default 10`

19.  `// 构造分页类`

20.  `Pageable pageable =  PageRequest.of(page, size);`

22.  `// 构造查询 NativeSearchQueryBuilder`

23.  `NativeSearchQueryBuilder searchQueryBuilder =  new  NativeSearchQueryBuilder()`

24.  `.withPageable(pageable)`

25.  `;`

26.  `if  (!StringUtils.isEmpty(keyword))  {`

27.  `// keyword must not null`

28.  `searchQueryBuilder.withQuery(QueryBuilders.queryStringQuery(keyword));`

29.  `}`

31.  `/*`

32.  `SearchQuery`

33.  `这个很关键,这是搜索条件的入口,`

34.  `elasticsearchTemplate 会 使用它 进行搜索`

35.  `*/`

36.  `SearchQuery searchQuery = searchQueryBuilder.build();`

38.  `// page search`

39.  `Page<PhoneModel> phoneModelPage = elasticsearchTemplate.queryForPage(searchQuery,  PhoneModel.class);`

41.  `// return`

42.  `return  Mono.just(Result.success(phoneModelPage));`

43.  `}`

官网文档也是这么用的,所以相对来说,这还是很简单的,不过拆词 和 搜索策略 搜索速度 可能在实际使用中要考虑。

2020年最新的常问企业面试题大全以及答案

高级搜索

先看代码,后面我们再来分析:

1.  `/**`

2.  `* 高级搜索,根据字段进行搜索`

3.  `* @param name 名称`

4.  `* @param color 颜色`

5.  `* @param sellingPoint 卖点`

6.  `* @param price 价格`

7.  `* @param start 开始时间(格式:yyyy-MM-dd HH:mm:ss)`

8.  `* @param end 结束时间(格式:yyyy-MM-dd HH:mm:ss)`

9.  `* @param page 当前页,从0开始`

10.  `* @param size 每页大小`

11.  `* @return {@link Result}`

12.  `*/`

13.  `@GetMapping("/_search")`

14.  `public  Mono<Result> search(String name,  String color,  String sellingPoint,  String price,  String start,  String  end,  int page,  int size)  {`

16.  `// 校验参数`

17.  `if  (StringUtils.isEmpty(page)  || page <  0)`

18.  `page =  0;  // if page is null, page = 0`

20.  `if  (StringUtils.isEmpty(size)  || size <  0)`

21.  `size =  10;  // if size is null, size default 10`

23.  `// 构造分页对象`

24.  `Pageable pageable =  PageRequest.of(page, size);`

26.  `// BoolQueryBuilder (Elasticsearch Query)`

27.  `BoolQueryBuilder boolQueryBuilder =  new  BoolQueryBuilder();`

28.  `if  (!StringUtils.isEmpty(name))  {`

29.  `boolQueryBuilder.must(QueryBuilders.matchQuery("name", name));`

30.  `}`

32.  `if  (!StringUtils.isEmpty(color))  {`

33.  `boolQueryBuilder.must(QueryBuilders.matchQuery("colors", color));`

34.  `}`

36.  `if  (!StringUtils.isEmpty(color))  {`

37.  `boolQueryBuilder.must(QueryBuilders.matchQuery("sellingPoints", sellingPoint));`

38.  `}`

40.  `if  (!StringUtils.isEmpty(price))  {`

41.  `boolQueryBuilder.must(QueryBuilders.matchQuery("price", price));`

42.  `}`

44.  `if  (!StringUtils.isEmpty(start))  {`

45.  `Date startTime =  null;`

46.  `try  {`

47.  `startTime =  DateTimeUtil.stringToDate(start,  DateTimeFormat.yyyy_MM_dd_HH_mm_ss);`

48.  `}  catch  (ParseException e)  {`

49.  `e.printStackTrace();`

50.  `}`

51.  `boolQueryBuilder.must(QueryBuilders.rangeQuery("createTime").gt(startTime.getTime()));`

52.  `}`

54.  `if  (!StringUtils.isEmpty(end))  {`

55.  `Date endTime =  null;`

56.  `try  {`

57.  `endTime =  DateTimeUtil.stringToDate(end,  DateTimeFormat.yyyy_MM_dd_HH_mm_ss);`

58.  `}  catch  (ParseException e)  {`

59.  `e.printStackTrace();`

60.  `}`

61.  `boolQueryBuilder.must(QueryBuilders.rangeQuery("createTime").lt(endTime.getTime()));`

62.  `}`

64.  `// BoolQueryBuilder (Spring Query)`

65.  `SearchQuery searchQuery =  new  NativeSearchQueryBuilder()`

66.  `.withPageable(pageable)`

67.  `.withQuery(boolQueryBuilder)`

68.  `.build()`

69.  `;`

71.  `// page search`

72.  `Page<PhoneModel> phoneModelPage = elasticsearchTemplate.queryForPage(searchQuery,  PhoneModel.class);`

74.  `// return`

75.  `return  Mono.just(Result.success(phoneModelPage));`

76.  `}`

不管spring如何封装,查询方式都一样,如下图:

image

好吧,我们怀着这样的心态去看下源码。

1.  `org.springframework.data.elasticsearch.core.query.SearchQuery`

这个是我们搜索需要用到对象

1.  `public  NativeSearchQueryBuilder withQuery(QueryBuilder queryBuilder)  {`

2.  `this.queryBuilder = queryBuilder;`

3.  `return  this;`

4.  `}`

OK,根据源码,我们需要构造这个 QueryBuilder,那么问题来了,这个是个什么东西,我们要如何构造,继续看:

1.  `org.elasticsearch.index.query.QueryBuilder`

注意包名。

啥,怎么又跑到 elasticsearch。

你想啊,你写的东西,会让别人直接操作吗?

答案是不会的,我们只会提供API,所有,不管Spring如何封装,也只会通过API去调用。

image

好吧,今天先到这里,下一个专题,我们再讨论关于搜索问题。

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值