本网站的搜索栏集成ElasticSearch实现全文检索和权重排序(SpringBoot)

原来本网站的搜索栏只能对文章标题进行模糊搜索,作为一个博客网站,这样的搜索效率很低,显然对于读者的搜索体验来说就非常不友好 时隔半月,作者终于有时间和精力将搜索引擎ElasticSearch集成进本网站了。。。

集成

本文默认已安装es在服务器,安装教程请看另一篇文章:ElasticSearch安装以及配置教程

创建索引

PUT /blog_new
{
  "mappings": {
    "properties": {
      "blogId": { "type": "long" },
      "blogTitle": { "type": "text","analyzer": "text_anlyzer",
        "search_analyzer": "ik_smart",
        "copy_to": "all" },
      "blogSubUrl": { "type": "ke、yword" },
      "blogCoverImage": { "type": "text" },
      "blogCategoryId": { "type": "integer" },
      "blogCategoryName": { "type": "text" },
      "blogTags": { "type": "text" },
      "blogStatus": { "type": "byte" },
      "blogViews": { "type": "long" },
      "enableComment": { "type": "byte" },
      "isDeleted": { "type": "byte" },
      "createTime": { "type": "date", "format": "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'" },
      "updateTime": { "type": "date", "format": "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'" },
      "blogContent": { "type": "text","analyzer": "text_anlyzer",
        "search_analyzer": "ik_smart",
        "copy_to": "all" },
      "all" : {
        "type": "text",
        "analyzer": "text_anlyzer",
        "search_analyzer": "ik_smart"
      }
    }
  },
  "settings": {
    "analysis": {
      "analyzer": {
        "text_anlyzer": {
          "tokenizer": "ik_max_word"
        }
      }
    }
  }
}

引入pom依赖

<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-elasticsearch</artifactId>
        </dependency>

添加es配置

spring.elasticsearch.uris=xxx.xxx.xxx.xxx
spring.elasticsearch.connection-timeout= 1s
spring.elasticsearch.socket-timeout= 30s

创建实体类

@Data
@AllArgsConstructor
@EqualsAndHashCode(callSuper = true)
@Document(indexName = "blog_new")
public class Blog {
    @Id
    private Long blogId;

    @Field(type = FieldType.Text,analyzer = "ik_max_word")
    private String blogTitle;

    @Field(index = false,type = FieldType.Keyword)
    private String blogSubUrl;

    @Field(index = false,type = FieldType.Keyword)
    private String blogCoverImage;

    @Field(index = false,type = FieldType.Integer)
    private Integer blogCategoryId;

    @Field(index = false,type = FieldType.Keyword)
    private String blogCategoryName;

    @Field(index = false,type = FieldType.Keyword)
    private String blogTags;

    @Field(index = false,type = FieldType.Byte)
    private Byte blogStatus;

    @Field(index = false,type = FieldType.Long)
    private Long blogViews;

    @Field(index = false,type = FieldType.Byte)
    private Byte enableComment;

    @Field(index = false,type = FieldType.Byte)
    private Byte isDeleted;

    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
    @Field(index = false,type = FieldType.Date)
    private Date createTime;

    @Field(index = false,type = FieldType.Date)
    private Date updateTime;

    @Field(type = FieldType.Text,analyzer = "ik_max_word",store = true)
    private String blogContent;
}

初始化数据

    @Autowired
    private ElasticsearchRestTemplate template; #注入template调用save()方法传入List批量导入数据

组装查询条件

BoolQueryBuilder boolQuery = QueryBuilders.boolQuery()
                    .should(QueryBuilders.matchQuery("blogContent", keyword).boost(1))
                    .should(QueryBuilders.matchQuery("blogTitle", keyword).boost(10)); #标题权重设置为10

            NativeSearchQuery searchQuery = new NativeSearchQueryBuilder()
                    .withQuery(functionScoreQuery(boolQuery))
                    .withPageable(PageRequest.of(page, size/*, Sort.by(Sort.Order.desc("createTime"))*/)) #此处注解可时间排序
                    //.withHighlightFields(
                    //        new HighlightBuilder.Field("blogContent").preTags("<em>").postTags("</em>"),
                    //        new HighlightBuilder.Field("blogTitle").preTags("<em>").postTags("</em>")
                    //)  #高亮显示,需要注意的是获得的Hits里面的数据是原数据,本就不会被修改,因此要继续拿highlight下的数据,即解析高亮结果,本文不做高亮处理


                    .build();

            SearchHits<Blog> searchHits = template.search(searchQuery, Blog.class);

总结

做完这些就可以实现标题所说功能了,但这还不够,我们还没有做es与mysql的一致性处理,这个我会抽时间来写,之前的文章有过分析:

关于es与mysql数据一致性的处理见解