初识elasticsearch

elasticsearch是一个非常强大的开源搜索引擎,可以帮助我们从海量的数据中快速搜索出想要的数据。
elasticsearch结合Kibina、Logstash、Beats,也就是elastic stack(ELK)。被广泛应用在日志分析、实时监控等领域。

elasticsearch底层是基于lucene来实现的。

Lucene是一个Java语言的搜索引擎类库,是Apache公司的顶级项目,由DougCutting于1999年研发。官网地址:https://lucene.apache.org/ 。
Lucene的优势:

  • 易扩展
  • 高性能(基于倒排索引)
    Lucene的缺点:
  • 只限于Java语言开发
  • 学习曲线陡峭
  • 不支持水平拓展

相比lucene,elasticsearch具备以下优势:

  • 支持分布式,可水平拓展
  • 提供Restful接口,可被任何语言调用

搜索引擎技术排名:
1、ElasticSearch:开源的分布式搜索引擎
2、Splunk:商业项目
3、Solr: Apache的开源搜索引擎

总结:

什么是elasticsearch?

  • 一个开源的分布式搜索引擎,可以用来实现搜索、日志统计、分析、系统监控等功能。

什么是elastic stack(ELK)?

  • 是以elasticsearch为核心的技术栈,包括Beats、Logstash、Kibana、Elasticsearch

什么是Lucene?

  • 是Apache开源的搜索引擎类库,提供了搜索引擎的核心API

什么是文档和词条

  • 每一条数据就是一个文档
  • 对文档中的内容分词 得到的词语就是词条

什么是正向索引

基于文档id创建索引,查找词条时必须先找到文档,而后判断是否包含词条

什么是倒排索引

对文档内容分词,对词条创建索引,并记录词条所在的文档信息,查询时先根据词条查询到文档id,而后获取到文档。

搜索流程:
举个例子:
搜索 华为手机 =>分词=>得到 “华为”、"手机"两个词条 =>去词条列表查询文档id=>得到每个词条的文档id=>根据文档id查询文档=>将查询出来的文档存入结果集

文档

elasticsearch时面向文档存储的,可以是数据库中的一条商品数据,一个订单信息。
文档数据会被序列化为json格式后存储在elasticsearch中

索引

索引: 相同类型的文档的集合
映射: 索引中文档的字段约束信息,类似表的结构约束

mysql和elasticsearch的概念对比:

mysql

elasticsearch

说明

Table

Index

索引(index)就是文档的集合,类似数据库的表(Table)

Row

Document

文档(document)就是数据库中的一条条数据,类似数据库中

的行(Row),文档都是JSON格式

Column

Field

字段(Field),就是JSON文档中的字段,类似数据库中的列(Column)

Schema

Mapping

映射(Mapping)是索引中文档的约束,例如字段类型的约束,类似数据库中的表结构(Schema)

SQL

DSL

DSL是elasticsearch提供的JSON风格的请求语句,用来操作elasticsearch,实现CRUD

架构区别

Mysql:擅长事务类型操作,可以确保数据的安全和一致性

Elasticsearch:擅长海量数据的搜索、分析、计算

java热门搜索 java搜索引擎排名_spring boot

安装es

//创建用户定义的网络(用于连接到同一网络的其他服务(例如 Kibana))
docker network create es-net
//安装es
docker run -d --name elasticsearch --net es-net -p 9200:9200 -p 9300:9300 -e "discovery.type=single-node" elasticsearch:7.17.6

安装kibana 并且绑定es

docker run -d --name kibana -e ELASTICSEARCH_HOSTS=http://es:9200 --network=elasticsearch-net -p 5601:5601 kibana:7.17.6

使用kibana模拟请求

到kibana的devtools的菜单 使用GET / 可以实现和localhost:9200 一样的效果 因为kibana绑定了es,所以不用写ip和端口,es请求都是走restFful风格的http请求

java热门搜索 java搜索引擎排名_elasticsearch_02

ik分词器

采用默认的分词器分词

java热门搜索 java搜索引擎排名_spring_03

安装ik分词器要注意的一点是ik分词器的版本一定要和elasticsearch版本完全一致,不然安装不上

ik分词器有两种模式 分别是 ik_smart和ik_max_word
ik_max_word: 会将文本做最细粒度的拆分,比如会将“中华人民共和国国歌”拆分为“中华人民共和国,中华人民,中华,华人,人民共和国,人民,人,民,共和国,共和,和,国国,国歌”,会穷尽各种可能的组合,适合 Term Query;

ik_smart: 会做最粗粒度的拆分,比如会将“中华人民共和国国歌”拆分为“中华人民共和国,国歌”,适合 Phrase 查询

拓展词库和停止词库

要拓展ik分词器的词库,只需要修改ik分词器目录中的config/analysis-ik/目录中的IKAnalyzer.cfg.xml文件

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">
<properties>
        <comment>IK Analyzer 扩展配置</comment>
        <!--用户可以在这里配置自己的扩展字典 这里我填的是 ext.dic-->
        <entry key="ext_dict">ext.dic</entry>
         <!--用户可以在这里配置自己的扩展停止词字典  *** 添加停用词词典 这里我填的是stopword.dic-->
        <entry key="ext_stopwords">stopword.dic</entry>
</properties>
在同级目录下创建ext.dic和stopword.dic
你要拓展的词放在ext.dic,你要停用的词放在stopword.dic即可

java热门搜索 java搜索引擎排名_spring_04

ik分词器的作用:

  • 创建倒排索引时对文档进行分词
  • 用户搜索时,对输入的内容分词

ik分词器有几种模式:

  • ik_smart:智能切分,粗粒度
  • ik_max_word:最细切分,细粒度

ik分词器如何拓展词条,如何停用词条:

  • 利用config目录下analysis-ik 下的IKAnalyzer.cfg.xml 添加拓展词典和停用词典实现的

索引库操作

mapping属性

mapping属性是对索引库中文档的约束,常见的mapping属性包括:

  • type:字段数据类型,常见的简单类型有:
  • 字符串: text(可分词的文本)、keyword(精确值,例如:品牌、国家、ip地址) 考虑字段时,如果有些词拆了没有意义,比如国家,品牌,那就选keyword 不能拆,否则就选text
    *数值: long、integer、short、byte、double、float
    *布尔: boolean
    *日期: date
    *对象: object
  • index: 是否创建索引,默认为true
  • analyzer: 使用哪种分词器
  • properties: 该字段的子字段

索引库操作

创建索引库
elasticsearch 通过Restful请求操作索引库,文档。请求内容用DSL语句来表示。创建索引库和mapping的DSL语法如下:
基本语法:

  • 请求方式: PUT
  • 请求路径: /索引库名,可自行定义
  • 请求参数: mapping映射

格式:

PUT /索引库名称
{
  "mappings": {
    "properties": {
      "字段名":{
        "type": "text",
        "analyzer": "ik_smart"
      },
      "字段名2":{
        "type": "keyword",
        "index": "false"
      },
      "字段名3":{
        "properties": {
          "子字段": {
            "type": "keyword"
          }
        }
      },
      // ...略
    }
  }
}
举个例子
PUT /christinaya
{
  "mappings": {
    "properties": {
      "info": {
        "type": "text",
        "analyzer": "ik_smart"
      },
      "email":{
        "type": "keyword"
      },
      "name":{
        "type": "object",
        "properties": {
          "firstName": {
            "type":"text",
            "analyzer":"ik_smart",
            "copy_to":"all"
          },
          "lastName":{
            "type":"text",
            "analyzer":"ik_smart",
            "copy_to":"all"
          }
        }
      },
      "location":{
        "type": "geo_point"
      },
      "all":{
      "type":"text",
      "analyzer":"ik_max_word"
      }

    }
  }
}

几个特殊字段说明:

  • location:地理坐标,里面包含精度、纬度
  • all:一个组合字段,其目的是将多字段的值 利用copy_to合并,提供给用户搜索

查看索引库

GET 索引库
GET liwenzhu

删除索引库

DELETE 索引库名
DELETE liwenzhu

修改索引库
索引库和mapping一旦创建就无法修改,但是可以添加新的字段,语法如下:

PUT /索引库名/_mapping
{
    "properties":{
        "新字段名"{
          "type":"integer"
        }
    }
}
举个例子:
PUT /liwenzhu/_mapping
{
  "properties":{
    "age":{
      "type":"integer"
    }
  }
}

文档操作

添加文档:
新增文档的DSL语句如下:

POST /索引库名/_doc/文档id
{
    "字段1": "值1",
    "字段2": "值2",
    "字段3": {
        "子属性1": "值3",
        "子属性2": "值4"
    },
    // ...
}
举个例子
# 新增文档

POST /christinaya/_doc/1
{
  "info":"李文铸学习java",
  "email":"237872788",
  "name":{
    "firstName":"李",
    "lastName":"文铸"
  }
}

查询文档

GET /{索引库名称}/_doc/{id}
举个例子
GET /christinaya/_doc/1

删除文档

DELETE /christinaya/_doc/1

java操作elasticsearch

主要使用的是spring-data-elasticsearch 因为感觉这个很好用 其他的工具也可以,主要是顺心顺手( •̀ ω •́ )

添加pom.xml依赖

<!--elasticsearch data-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-elasticsearch</artifactId>
</dependency>
<!--我study主要写在测试类里面 所以导入测试类依赖-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
    <version>2.7.5</version>
    <scope>test</scope>
</dependency>
<!-- 单元测试依赖 -->
<dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>4.12</version>
</dependency>

编写yml文件

server:
  port: 8080
spring:
  elasticsearch:
    uris: localhost:9200

编写实体类

package com.example.elasticsearchstudy.domain;

import lombok.Data;
import org.springframework.data.annotation.Id;
import org.springframework.data.elasticsearch.annotations.Document;
import org.springframework.data.elasticsearch.annotations.Field;
import org.springframework.data.elasticsearch.annotations.FieldType;
import org.springframework.stereotype.Component;

import java.io.Serializable;


/**
 * @author liwenzhu
 */
@Component
@Data
@Document(indexName = "hotel")
public class Hotel implements Serializable {

    /** 酒店id*/
    @Id
    private String id;

    /** 酒店名称*/
    @Field(type = FieldType.Keyword)
    private String name;

    /** 酒店地址 */
    @Field(type = FieldType.Keyword)
    private String address;

    /** 酒店价格 */
    @Field(type = FieldType.Double)
    private Integer price;

    /** 酒店评分 */
    @Field(type = FieldType.Double)
    private Double score;

    /** 酒店品牌 */
    @Field(type = FieldType.Keyword)
    private String brand;

    /** 所在城市 */
    @Field(type = FieldType.Keyword)
    private String city;

    /** 酒店星级 酒店星级,1星到5星,1钻到5钻 */
    @Field(type = FieldType.Keyword)
    private String starName;

    /** 商圈 */
    @Field(type = FieldType.Text,analyzer = "ik_max_word")
    private String business;

    /** 纬度 */
    @Field(type = FieldType.Keyword)
    private String latitude;

    /** 经度 */
    @Field(type = FieldType.Keyword)
    private String longitude;

    /** 酒店图片 */
    @Field(type = FieldType.Keyword)
    private String pic;
}

新建一个repository/HotelRepository

package com.example.elasticsearchstudy.repository;

import com.example.elasticsearchstudy.domain.Hotel;
import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;
import org.springframework.stereotype.Service;

/**
 * @author liwenzhu
 */
@Service
public interface HotelRepository extends ElasticsearchRepository<Hotel,String> {
}

编写测试类

package com.example.elasticsearchstudy;

import com.example.elasticsearchstudy.domain.Hotel;
import com.example.elasticsearchstudy.repository.HotelRepository;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

import javax.annotation.Resource;

@RunWith(SpringRunner.class)
@SpringBootTest
public class LiwenzhuTest {
    @Resource
    private HotelRepository repository;

    @Test
    public void testCreateDoc() {
        Hotel hotel = new Hotel();
        hotel.setName("京西大酒店");
        hotel.setAddress("xxx路");
        hotel.setPrice(2000);
        hotel.setScore(4.0);
        hotel.setBrand("李文铸牌");
        hotel.setCity("福州");
        hotel.setStarName("四星");
        hotel.setBusiness("福州儿童公园路");
        hotel.setLatitude("30.251433");
        hotel.setLongitude("120.47522");
        hotel.setPic("https://m.tuniucdn.com/filebroker/cdn/res/07/36/073662e1718fccefb7130a9da44ddf5c_w200_h200_c1_t0.jpg");
        repository.save(hotel);
    }
}

因为是spring-data-elasticsearch 所以crud是遵循spring-data的风格的

增加和修改都是save方法

删除就是delete方法,不过他删除都是根据id删的,所以要么deleteById,要么就是delete实体类的id有值

查询遵循spring-data风格

比如你的方法名叫做:findByTitle,那么它就知道你是根据title查询,然后自动帮你完成,无需写实现类。

java热门搜索 java搜索引擎排名_字段_05


最后附上代码

github: https://github.com/liwenzhu5113/elasticsearch-study.git

如果对你有帮助,点个赞👍吧