微服务:索引库、文档操作

分词器

处理中文分词,一般会使用IK分词器。https://github.com/medcl/elasticsearch-analysis-ik

  • ik_smart:最少切分
  • ik_max_word:最细切分
POST /_analyze
#post请求,解析
{
  "text": "兽兽真香,燕燕也香。",
  "analyzer": "ik_smart"
}
#ik_smart输出结果为
{
  "tokens" : [
    {
      "token" : "兽",
      "start_offset" : 0,
      "end_offset" : 1,
      "type" : "CN_CHAR",
      "position" : 0
    },
    {
      "token" : "兽",
      "start_offset" : 1,
      "end_offset" : 2,
      "type" : "CN_CHAR",
      "position" : 1
    },
    {
      "token" : "真香",
      "start_offset" : 2,
      "end_offset" : 4,
      "type" : "CN_WORD",
      "position" : 2
    },
    {
      "token" : "燕燕",
      "start_offset" : 5,
      "end_offset" : 7,
      "type" : "CN_WORD",
      "position" : 3
    },
    {
      "token" : "也",
      "start_offset" : 7,
      "end_offset" : 8,
      "type" : "CN_CHAR",
      "position" : 4
    },
    {
      "token" : "香",
      "start_offset" : 8,
      "end_offset" : 9,
      "type" : "CN_CHAR",
      "position" : 5
    }
  ]
}
#ik_max_word输出结果为

扩展词词典

随着互联网的发展,“造词运动”也越发的频繁。出现了很多新的词语,在原有的词汇列表中并不存在。比如:“奥力给”,“传智播客” 等。

所以我们的词汇也需要不断的更新,IK分词器提供了扩展词汇的功能。

打开IK分词器config目录:

image-20210506112225508

2)在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>
        <!--用户可以在这里配置自己的扩展字典 *** 添加扩展词典-->
        <entry key="ext_dict">ext.dic</entry>
</properties>

3)新建一个 ext.dic,可以参考config目录下复制一个配置文件进行修改

奥力给

4)重启elasticsearch

docker restart es

# 查看 日志
docker logs -f elasticsearch

image-20201115230900504

日志中已经成功加载ext.dic配置文件

5)测试效果:

GET /_analyze
{
  "analyzer": "ik_max_word",
  "text": "就业超过90%,奥力给!"
}

注意当前文件的编码必须是 UTF-8 格式,严禁使用Windows记事本编辑

停用词词典

在互联网项目中,在网络间传输的速度很快,所以很多语言是不允许在网络上传递的,如:关于宗教、政治等敏感词语,那么我们在搜索时也应该忽略当前词汇。

IK分词器也提供了强大的停用词功能,让我们在索引时就直接忽略当前的停用词汇表中的内容。

1)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>
        <!--用户可以在这里配置自己的扩展字典-->
        <entry key="ext_dict">ext.dic</entry>
         <!--用户可以在这里配置自己的扩展停止词字典  *** 添加停用词词典-->
        <entry key="ext_stopwords">stopword.dic</entry>
</properties>

3)在 stopword.dic 添加停用词


分词器的作用是什么?

  • 创建倒排索引时对文档分词

  • 用户搜索时,对输入的内容分词

IK分词器有几种模式?

  • ik_smart:智能切分,粗粒度

  • ik_max_word:最细切分,细粒度

IK分词器如何拓展词条?如何停用词条?

  • 利用config目录的IkAnalyzer.cfg.xml文件添加拓展词典和停用词典

  • 在词典中添加拓展词条或者停用词条


索引库

Mapping——映射

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

  • type:字段数据类型,常见的简单类型有:

    • 字符串:text(可分词的文本)、keyword(精确值,例如:品牌、国家、ip地址)

    • 数值:long、integer、short、byte、double、float、

    • 布尔:boolean

    • 日期:date

    • 对象:object

  • index:是否创建索引,默认为true

  • analyzer:使用哪种分词器

  • properties:该字段的子字段


创建索引库

#如:
PUT /heima
{
  "mappings": {
    "properties": {
      "info":{
        "type": "text",
        "analyzer": "ik_smart"
      },
      "email":{
        "type": "keyword",
        "index": "false"
      },
      "name":{
        "properties": {
          "firstName": {
            "type": "keyword"
          }
        }
      },
      // ... 略
    }
  }
}

查看索引库

GET /索引库名 
#举例:
GET /heima

删除索引库

DELETE /索引库名 
#举例:
DELETE /heima

修改索引库

ES中禁止修改索引库。

但是可以新增字段名

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

文档操作

新增文档

POST /索引库名/_doc/文档id
#如:
POST /heima/_doc/1
{
    "info": "黑马程序员Java讲师",
    "email": "zy@itcast.cn",
    "name": {
        "firstName": "云",
        "lastName": "赵"
    }
}

查询文档

GET /索引库名/_doc/文档id 
#如:
GET /heima/_doc/1 

删除文档

DELETE /索引库名/_doc/文档id 
#如:
DELETE /heima/_doc/1 

修改文档

  • 方式一:全量修改,会删除旧文档,添加新文档
PUT /索引库名/_doc/文档id
#如:
PUT /heima/_doc/1
{
    "info": "黑马程序员高级Java讲师",
    "email": "zy@itcast.cn",
    "name": {
        "firstName": "云",
        "lastName": "赵"
    }
}

如果文档id不存在,则不会删除,但是会创建新的文档

  • 增量修改
POST /索引库名/_update/文档id
#如:
POST /heima/_update/1
{
  "doc": {
    "email": "ZhaoYun@itcast.cn"
  }
}

使用java操作索引库和文档

利用JavaRestClient实现创建、删除索引库,判断索引库是否存在
基本步骤如下:

  • 分析数据结构,定义mapping属性
PUT /hotel
{
  "mappings": {
    "properties": {
      "id": {
        "type": "keyword"
      },
      "name":{
        "type": "text",
        "analyzer": "ik_max_word",
        "copy_to": "all"
      },
      "address":{
        "type": "keyword",
        "index": false
      },
      "price":{
        "type": "integer"
      },
      "score":{
        "type": "integer"
      },
      "brand":{
        "type": "keyword",
        "copy_to": "all"
      },
      "city":{
        "type": "keyword",
        "copy_to": "all"
      },
      "starName":{
        "type": "keyword"
      },
      "business":{
        "type": "keyword"
      },
      "location":{
        "type": "geo_point"
      },
      "pic":{
        "type": "keyword",
        "index": false
      },
      "all":{
        "type": "text",
        "analyzer": "ik_max_word"
      }
    }
  }
}

copy_to说明:

image-20210720222221516

  • 初始化JavaRestClient

    • 引入依赖
    <dependency>
        <groupId>org.elasticsearch.client</groupId>
        <artifactId>elasticsearch-rest-high-level-client</artifactId>
    </dependency>
    
    • 因为SpringBoot默认的ES版本是7.6.2,所以我们需要覆盖默认的ES版本:
    <properties>
            <java.version>1.8</java.version>
            <elasticsearch.version>7.12.1</elasticsearch.version>
    </properties>
    
    • 初始化RestHighLevelClient:
    public class HotelIndexTest {
        private RestHighLevelClient client;
    
        /**
         * 这个方法用来初始化client
         */
        @BeforeEach
        void setUp() {
            this.client=new RestHighLevelClient(RestClient.builder(
                
                    HttpHost.create("192.168.1.2:9200")
            ));
        }
    
        /**
         * 这个方法用来销毁client
         * @throws IOException
         */
        @AfterEach
        void tearDown() throws IOException {
            this.client.close();
        }
    
        @Test
        void test1(){
            //测试逻辑
        }
    }
    
  • 利用JavaRestClient创建索引库

    /**
     * 这个方法用来创建索引库
     * @throws IOException
     */
    @Test
    void create() throws IOException {
        //1.创建Request对象
        CreateIndexRequest request = new CreateIndexRequest("hotel");
    
        //2.准备请求参数:DSL语句
        request.source(MAPPING_TEMPLATE, XContentType.JSON);
    
        //3.发送请求
        client.indices().create(request, RequestOptions.DEFAULT);
    }
    
  • 利用JavaRestClient删除索引库

    /**
     * 这个方法用来删除索引库
     * @throws IOException
     */
    @Test
    void delete() throws IOException {
        //1.创建Request对象
        DeleteIndexRequest request = new DeleteIndexRequest("hotel");
    
        //2.发送请求
        client.indices().delete(request, RequestOptions.DEFAULT);
    }
    
  • 利用JavaRestClient判断索引库是否存在

    /**
     * 这个方法用来判断索引库是否存在
     * @throws IOException
     */
    @Test
    void isExist() throws IOException {
        //1.创建Request对象
        GetIndexRequest request = new GetIndexRequest("hotel");
        //2.发送请求
        boolean exists = client.indices().exists(request, RequestOptions.DEFAULT);
        //3.输出
        System.out.println(exists?"索引库已经存在":"索引库不存在");
    }
    
posted @ 2022-03-27 23:38  Boerk  阅读(66)  评论(0编辑  收藏  举报