ElasticSearch-全文检索

一、基本概念
    1、Index(索引):名词,相当于 MySQL 中的 Database
    2、Type(类型):类似于 MySQL 中的 Table;每一种类型的数据放在一起
    3、Document(文档):文档是 JSON 格式的,Document 就像是 MySQL 中的某个 Table 里面的内容;
    4、倒排索引机制
二、Docker 安装 Es
    1、下载镜像文件
    docker pull elasticsearch:7.4.2 存储和检索数据
          docker pull kibana:7.4.2 可视化检索数
          docker   images  :查看已经安装镜像
      free -m  :查看内存
    2、创建实例
    1)、ElasticSearch
        mkdir -p /mydata/elasticsearch/config
        mkdir -p /mydata/elasticsearch/data
        echo "http.host: 0.0.0.0" >> /mydata/elasticsearch/config/elasticsearch.yml

         cat elasticsearch.yml  :查看内容

        chmod -R 777 /mydata/elasticsearch/  保证权限

         docker run --name elasticsearch -p 9200:9200 -p 9300:9300 \
        -e "discovery.type=single-node" \
        -e ES_JAVA_OPTS="-Xms64m -Xmx512m" \
        -v /mydata/elasticsearch/config/elasticsearch.yml:/usr/share/elasticsearch/config/elasticsearch.yml \
        -v /mydata/elasticsearch/data:/usr/share/elasticsearch/data \
        -v /mydata/elasticsearch/plugins:/usr/share/elasticsearch/plugins \
        -d elasticsearch:7.4.2

      然后就在9200端口启动了,URL输入http://192.168.56.10:9200 
    重启操作:   docker ps -a  ;查看(包括未启动的)
                         docker start 18a
    开机自启动:docker update 18a(id号) --restart=always
    删除操作:docker stop 18a;
                      docker rm 18a;
                      docker ps -a   

    2)、Kibana
    docker run --name kibana -e ELASTICSEARCH_HOSTS=http://192.168.56.10:9200 -p 5601:5601 -d kibana:7.4.2
     开机自启动:docker update 455(id号) --restart=always

三、初步检索
1、_cat
GET /_cat/nodes:查看所有节点
GET /_cat/health:查看 es 健康状况
GET /_cat/master:查看主节点
GET /_cat/indices:查看所有索引 相当于show databases;
2、索引一个文档(保存一条记录)
   保存一个数据,保存在哪个索引的哪个类型下,指定用哪个唯一标识
   http://192.168.56.10:9200/customer/external/1     :;在 customer 索引下的 external 类型下保存 1 号数据为
  put请求:{ "name": "John Doe"}

PUT 和 POST保存更新 都可以,
POST 新增。如果不指定 id,会自动生成 id。指定 id 就会修改这个数据,并新增版本号
PUT 可以新增可以修改。PUT 必须指定 id;由于 PUT 需要指定 id,我们一般都用来做修改操作,不指定 id 会报错。

 3、查询文档
    GET customer/external/1        

    更新请求:http://192.168.56.10:9200/customer/external/1?if_seq_no=2&if_primary_term=1   乐观锁机制
4、更新文档
方式一:
POST customer/external/1/_update
{ "doc":{ "name": "John Doew"
}
}
方式二:
POST customer/external/1
{ "name": "John Doe2"
}
方式三:
PUT customer/external/1
{ "name": "John Doe"
}
POST和PUT不带_updata得不对比原先数据,带_updata得对比原先数据,相同就不会有任何操作
5、删除文档&索引
    1、DELETE customer/extern  删除文档
    2、DELETE custome   删除索引
6、bulk 批量 API

https://github.com/elastic/elasticsearch/blob/7.4/docs/src/test/resources/accounts.json?raw=true 导入测试数据
    POST bank/account/_bulk
    测试数据

四、进阶检索

手册官网:https://www.elastic.co/guide/en/elasticsearch/reference/current/mapping.html
1、SearchAPI

ES 支持两种基本方式检索 :
⭐一个是通过使用 REST request URI 发送搜索参数(uri+检索参数)
⭐另一个是通过使用 REST request body 来发送它们(uri+请求体)
第一种方式:一切检索从_search 开始  :GET bank/_search?q=*&sort=account_number:asc
第二种方式: uri+请求体进行检索:
 

GET bank/_search
{
  "query": {
    "match_all": {}
  },
  "sort": [
    {
      "account_number": {
        "order": "desc"
      }
    }
  ]
}

2、Query DSL
1)、基本语法格式
2)、返回部分字段:  "_source": ["age","balance"]

GET bank/_search
{
  "query": {
    "match_all": {}
  },
  "sort": [
    {
      "balance": {
        "order": "desc"
      }
    }
  ],
  "from":0
  , "size": 5,
  "_source": ["age","balance"]
}


3)、match【匹配查询】  全文检索
⭐ 基本类型(非字符串),精确匹配
⭐ 字符串,全文检索
⭐字符串,多个单词(分词+全文检索)

GET bank/_search
{
  "query": {
    "match": {
      "address": "mill road"
    }
  }
}


##全文检索按照评分进行排序,会对检索条件分词匹配

4)、match_phrase【短语匹配】

GET bank/_search
{
  "query": {
    "match_phrase": {
      "address": "mill road"
    }
  }
}

5)、multi_match【多字段匹配】
###也会进行分词

GET bank/_search
{
  "query": {
    "multi_match": {
      "query": "mill",
      "fields": ["state","address"]
    }
  }
}


6)、bool【复合查询】
⭐must:必须达到 must 列举的所有条件
⭐must_not 必须不是指定的情况
⭐should:应该达到 should 列举的条件,如果达到会增加相关文档的评分,并不会改变查询的结果。

GET bank/_search
{
  "query": {
    "bool": {
      "must": [
        {
          "match": {"address": "mill"}
        },
        {
          "match": {"gender": "M"}
        }
      ],
      "should": [
        {
          "match": {"address": "lane"}
        }
      ],
      "must_not": [
        {
          "match": {"email": "baluba.com"}
        }
      ]
    }
  }
}


7)、filter【结果过滤】
并不是所有的查询都需要产生分数,特别是那些仅用于 “filtering”(过滤)的文档。不会产生查询分数
8)、term
和 match 一样。匹配某个属性的值。全文检索字段用 match,其他非 text 字段匹配用 term
 

GET bank/_search
{
  "query": {
    "bool": {
      "must": [
        {
          "term": {"age": {"value": "28"}}
        },
        {
          "match": {"address": "990 Mill Road"}
        }
      ]
    }
  }
}

9)、aggregations(执行聚合)
##复杂:查出所有年龄分布,并且这些年龄段中 M 的平均薪资和 F 的平均薪资以及这个年龄段的总体平均薪资

GET bank/account/_sea
GET bank/_search
{
  "query": {
    "match_all": {}
  },
  "aggs": {
    "avg_age": {
      "terms": {
        "field": "age",
        "size": 10
      },
      "aggs": {
        "male": {
          "terms": {
            "field": "gender.keyword",
            "size": 10
          },
          "aggs": {
            "avg_bal": {
              "avg": {"field": "balance"}
            }
          }
        },
        "balance_avg":{
          "avg": {
            "field": "balance"
          }
        }
      }
    }
  }
}


3、Mapping 映射
手册官网:https://www.elastic.co/guide/en/elasticsearch/reference/current/mapping.html
GET bank/_mapping  :查询bank索引下的属性映射
1)、创建映射
 

PUT /my-index
{
  "mappings": {
    "properties": {
      "age": {
        "type": "integer"
      },
      "email": {
        "type": "keyword"    //创建的是一个精确索引
      },
      "name": {
        "type": "text"            //创建的是一个全局索引
      }
    }
  }
}

2)、添加新的字段映射

PUT /my-index/_mapping
{
  "properties": {
    "employee-id": {
      "type": "keyword",
      "index": false
    }
  }
}


3)、更新映射
对于已经存在的映射字段,我们不能更新。更新必须创建新的索引进行数据迁移
4)、数据迁移
先创建出 new_twitter 的正确映射。然后使用如下方式进行数据迁移

POST _reindex
{
  "source": {
    "index": "twitter",
    "type": "tweet         #当老版本中有类型,故还要加上这一行
  },
  "dest": {
    "index": "new_twitter"
  }
}

4、

1)分词--安装ik分词器
将elasticsearch-analysis-ik-5.6.11.zip  解压之后放在/mydata/elasticsearch/plugins下

⭐⭐⭐一个遇到的问题,就是在plugins放入解压后的ik之后再重启elasticsearch之后,elasticsearch一直不断重启,问题解决的方案是elasticsearch
版本要和ik版本一致,我的都是7.4.2

补充:
使用MobaXterm,可以实现windos和linux的文件互传,
chmod -R 777 ik/   改变文件夹 ik/ 的权限为可读可写可执行
docker exec -it 18a /bin/bash  :进入docker中的18a项目中
exit;  退出docker
docker restart elasticsearch :   重启elasticsearch

⭐修改linux网络配置:
1、cd /etc/sysconfig/network-scripts/
2、ls
3、 ip addr 查看我们使用的是哪个网络
4、vi ifcfg-eth1
添加:
GATEWAY=192.168.56.1
DNS1=114.114.114.114
DNS2=8.8.8.8
5、重启网络 :service network restart    
6、ping baidu.com


curl -o /etc/yum.repos.d/CentOS-Base.repo http://mirrors.163.com/.help/CentOS7-Base-163.repo

更改Linux yum源:
更改方法:
1、进入yum配置文件目录
cd /etc/yum.repos.d/
2、备份配置文件
mv CentOS-Base.repo CentOS-Base.repo.bak
3、下载163的配置,并改名
curl -o /etc/yum.repos.d/CentOS-Base.repo http://mirrors.163.com/.help/CentOS7-Base-163.repo
4、生成缓存
yum makecach

2)分词--安装ik分词器
POST _analyze
{
  "analyzer": "ik_smart",
  "text": "我是中国山东人"
}

安装 nginx:
1、docker下载nginx: docker run -p 80:80 --name nginx -d nginx:1.10
2、在mydata\下创建 nginx文件夹
3、将docker容器内的 nginx文件夹放到mydata下:docker container cp nginx:/etc/nginx  .
4、停止并移除docker里面的nginx:
docker stop nginx
docker rm nginx
5、在mydata下创建conf文件夹,将nginx文件目录里面的文件放到conf下,然后清空nginx,然后将conf放到nginx里面
6、创建新的nginx
docker run -p 80:80 --name nginx \
-v /mydata/nginx/html:/usr/share/nginx/html \
-v /mydata/nginx/logs:/var/log/nginx \
-v /mydata/nginx/conf:/etc/nginx \
-d nginx:1.10
7、cd /mydata/nginx/html
8、vi index.html

输入i进入插入模式:  
<h1>Guilimall</h1>
9、在/mydata/nginx/html 下mkdir es
10、cd /mydata/nginx/html/es
       vi fenci.txt 
      加入自定义分词如:尚硅谷
10、游览器输入:http://192.168.56.10/es/fenci.txt
       就可以看到效果了,之后有想加入的自定义词汇就可以加到fenci.txt文件下
11、cd /mydata/elasticsearch/plugins/ik/config
12、vi IKAnalyzer.cfg.xml
加入:
<!--用户可以在这里配置远程扩展字典 -->
        <entry key="remote_ext_dict">http://192.168.56.10/es/fenci.txt</entry>
13、docker restart elasticsearch
14、
POST _analyze
{
  "analyzer": "ik_max_word",
  "text": "尚硅谷机构"
}

附录:

SpringBoot 整合elasticSearch:
1、创建一个springboot项目,版本为<version>2.1.8.RELEASE</version>,导入spring-web依赖和common依赖
2、导入es的rest-high-level-client

<dependency>
<groupId>org.elasticsearch.client</groupId>
<artifactId>elasticsearch-rest-high-level-client</artifactId>
<version>7.4.2</version>
</dependency>

这个版本要和使用的elasticsearch版本对应,springboot默认给添加了elasticsearch版本,这时候需要添加

<properties>
        <java.version>1.8</java.version>
        <elasticsearch.version>7.4.2</elasticsearch.version>
 </properties>


3、因为导入的common依赖中包括一些数据库的依赖,此时启动文件GulimallSearchApplication需要排除数据库

@SpringBootApplication(exclude = DataSourceAutoConfiguration.class)

4、开启nacos注册中心,将该模块注册进入nacos注册中心

在application.properties中写入:
spring.cloud.nacos.config.server-addr=127.0.0.1:8848
spring.application.name=gulimall-search
并开启@EnableDiscoveryClient  注册发现

5、编写配置,给容器中注入一个RestHighLevelClient

@Configuration
public class GulimallElasticSearchConfig {
    @Bean
    public RestHighLevelClient esRestClient(){

       RestClientBuilder builder =null;
       builder = RestClient.builder(new HttpHost("192.168.56.10", 9200, "http"));
       RestHighLevelClient client = new RestHighLevelClient(builder);
       return client;
    }
}

java测试篇:
一:测试容器中是否已经注入了RestHighLevelClient
 

@RunWith(SpringRunner.class)
@SpringBootTest
public class GulimallSearchApplicationTests {

    @Autowired
    private RestHighLevelClient client;
    @Test
    public void contextLoads() {
        System.out.println(client);
    }
}


二、测试存储、更新ES数据
参考文档API:https://www.elastic.co/guide/en/elasticsearch/client/java-rest/current/java-rest-high-document-index.html
   

 @Test
    public void indexData() throws IOException {
        //创建索引
        IndexRequest indexRequest = new IndexRequest("users");
        //数据的id
        indexRequest.id("1");
        User user = new User();
        user.setUserName("zhangsan");
        user.setAge(18);
        user.setGender("男");

        String jsonString = JSON.toJSONString(user);
        indexRequest.source(jsonString, XContentType.JSON);
        //执行索引保存操作
        IndexResponse index = client.index(indexRequest, GulimallElasticSearchConfig.COMMON_OPTIONS);
        //提取有用的响应数据
        System.out.println(index);
    }

    @Data
    class User {
        private String userName;
        private String gender;
        private Integer age;
    }


三、复杂检索:在bank中搜索address中包含mill的所有人的年龄分布以及平均年龄,平均薪资
参考文档API:https://www.elastic.co/guide/en/elasticsearch/client/java-rest/current/java-rest-high-search.html
利用在线软件将json生成java实体类:https://www.bejson.com/json2javapojo/new/
   

@ToString
    @Data
    static class Account {
        private int account_number;
        private int balance;
        private String firstname;
        private String lastname;
        private int age;
        private String gender;
        private String address;
        private String employer;
        private String email;
        private String city;
        private String state;
    }

    @Test
    public void searchData() throws IOException {
        //1. 创建检索请求
        SearchRequest searchRequest = new SearchRequest();
        //1.1)指定索引
        searchRequest.indices("bank");
        //1.2)构造检索条件
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        sourceBuilder.query(QueryBuilders.matchQuery("address", "Mill"));
//        System.out.println("检索条件:"+sourceBuilder.toString());
        
        //1.2.1)按照年龄分布进行聚合
        TermsAggregationBuilder ageAgg = AggregationBuilders.terms("ageAgg").field("age").size(10);
        sourceBuilder.aggregation(ageAgg);

        //1.2.2)计算平均年龄
        AvgAggregationBuilder ageAvg = AggregationBuilders.avg("ageAvg").field("age");
        sourceBuilder.aggregation(ageAvg);
        //1.2.3)计算平均薪资
        AvgAggregationBuilder balanceAvg = AggregationBuilders.avg("balanceAvg").field("balance");
        sourceBuilder.aggregation(balanceAvg);
//        System.out.println("检索条件:" + sourceBuilder.toString());

        searchRequest.source(sourceBuilder);
        //2. 执行检索
//        SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);
        SearchResponse searchResponse = client.search(searchRequest, GulimallElasticSearchConfig.COMMON_OPTIONS);
        System.out.println("检索结果:" + searchResponse.toString());
        
        //3. 将检索结果封装为Bean
        //得到第一层的hits
        SearchHits hits = searchResponse.getHits();
        //得到第二层的hits
        SearchHit[] searchHits = hits.getHits();
        for (SearchHit searchHit : searchHits) {
            String sourceAsString = searchHit.getSourceAsString();
            Account account = JSON.parseObject(sourceAsString, Account.class);
            System.out.println(account);

        }
//        //4. 获取聚合信息
        Aggregations aggregations = searchResponse.getAggregations();

        Terms ageAgg1 = aggregations.get("ageAgg");
        for (Terms.Bucket bucket : ageAgg1.getBuckets()) {
            String keyAsString = bucket.getKeyAsString();
            System.out.println("年龄:" + keyAsString + " ==> " + bucket.getDocCount());
        }
        Avg balanceAvg1 = aggregations.get("balanceAvg");
        System.out.println("平均薪资:" + balanceAvg1.getValue());
    }
     


        

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值