ElasticSearch入门

最近学习所得,欢迎大家指正!

目录

ES简介

ES安装

IK分词器安装

ES名词解释

普通操作

Index

Type

Document

JavaAPI

获取Client

创建Index和Type

Document

批量插入

批量删除

批量查询


ES简介

ElasticSearch是使用Java语言基于Lucene开发的一款软件,通过Lucene实现所有的索引和搜索功能。但它通过Restful API影藏了Lucene的复杂性。

ElasticSearch的特点:

  • 分布式的实时文件索引,每个字段都可以被用于搜索
  • 分布式的实时分析搜索引擎
  • 可以横向扩展,同时可以处理结构化及非结构化数据

ES安装

注意:需要用到Java环境,在这里我是用的是6.2.3版本的ES

  1. 下载
    wget https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-6.2.3.zip
  2. 解压
    unzip elasticsearch-6.2.3.zip
  3. 配置
    #目录是ES安装目录下的config/elasticsearch.yml
    network.host: 0.0.0.0
  4. 启动
    nohup ./bin/elasticsearch >/dev/null 2>&1 &

可能有错误,解决方法如下:

编辑 /etc/security/limits.conf,追加内容:
 

* soft nofile 65536
* hard nofile 65536

编辑 /etc/sysctl.conf,追加内容:

vm.max_map_count=655360

执行:

sysctl -p

IK分词器安装

注意:IK的版本要与ES的版本一致!

./bin/elasticsearch-plugin install https://github.com/medcl/elasticsearch-analysis-ik/releases/download/v6.2.3/elasticsearch-analysis-ik-6.2.3.zip

ES名词解释

名词解释
Index

索引就是像关系数据库中的“数据库”。通过映射可以定义成多种类型。索引是一个逻辑命名空间映射到一个或多个主要的分片,可以有零个或多个副本分片。

TypeType是相当于关系数据库中的“”。每种类型都有一列字段,用来定义文档的类型。映射定义了对在文档中的每个字段如何进行分析。
Document

文档是存储在elasticsearch中的一个JSON文件。这是相当与关系数据库中表的一行数据。每个文档被存储在索引中,并具有一个类型和一个id。

  一个文档是一个JSON对象(也被称为在其他语言中的 hash / hashmap / associative array(关联数组)),其中包含零个或多个字段 或者 键值对。

  原始JSON文档将被存储在索引的_source字段,在获得(getting)或者 搜索(searching)默认的返回时,得到或搜索文档。

Fields

文档中包含的一组字段或键值对。字段的值可以是一个简单的(标量)值(如字符串,整数,日期),或者一个嵌套的结构就像一个数组或对象。一个字段就是类似关系数据库表中的一

  映射的每个字段有一个字段的类型“type”(不要与文档类型混淆),表示那种类型的数据可以存储在该字段里,如:整数<integer>,字符串<string>,对象<object>。

  映射还允许你定义(除其他事项外)一个字段的值如何进行分析。

Id

每个文档ID标识了一个文档。一个文档的索引/类型/ID必须是唯一的。如果没有提供ID,将是自动生成。(还可以看到路由<routing>)

Mapping

映射是像关系数据库中的”模式定义“。每个索引都有一个映射,它定义了每个索引的类型,再加上一些索引范围的设置。映射可以被明确地定义,或者在一个文档被索引的时候自动生成。

Cluster

一个集群包含了一个或多个分配了相同集群名的节点。每个集群都有一个集群自选出的主节点。并且可以决定主节点失败后哪些节点可以替换主节点。

Node

节点是属于elasticsearch集群的运行实例。测试的时候,在一台服务器可以启动多个节点,但通常情况下一台服务器启动一个节点,在启动时节点将使用淡泊(或组播,但必须指定)来发现使用相同的集群名称的集群,并会尝试加入该节点。

Shard

相当于横向切分了Index,每个文档都存储在一个主要分片上。当你索引一个文档时,索引首先生成在主分片上。还有n份副本分片。默认五个主分片,每个分片有三个副本。我们需要知道:分片就是一个Lucene实例。在索引建立之后分片数数是不可以修改的。

replica

一个分片默认会有三个副本,主要防止硬件损坏丢失数据,同时提供读数据服务。在索引建立之后副本数是可以修改的。

Routing

我们知道一个文档是存在一个主分片中的,我们通常通过路由件的hash值去确定文档所在的主分片,Routing键通常是id,我们也可以在查询的时候去指定。

Term

精准值检索。

Analysis

就将full txt转换成术语/分词,这取决于使用哪个分词器,,拆分后的词存储在索引中,当被检索时,检索条件也会被分词器处理,来匹配存储在索引中的分词。

普通操作

在操作时要添加一个:

curl -H "Content-Type: application/json"

Index

#新增Index,注意index不能有大写
curl -X PUT 'localhost:9200/indexname'
#删除Index
curl -X DELETE 'localhost:9200/indexname'
#查看所有Index
curl 'localhost:9200/_cat/indices?v'   

Type

#创建Type
curl -X PUT 'localhost:9200/indexname' -d '
{
  "mappings": {
    "typename": {
      "properties": {
        "fieldname": {
          "type": "text"
        },
        "fieldname": {
          "type": "text"
        },
        "fieldname": {
          "type": "text"
        }
      }
    }
  }
}'


#创建Type时指定分词器
curl -X PUT 'localhost:9200/indexname' -d '
{
  "mappings": {
    "typename": {
      "properties": {
        "fieldname": {
          "type": "text",
          "analyzer": "ik_max_word",
          "search_analyzer": "ik_max_word"
        },
        "fieldname": {
          "type": "text",
          "analyzer": "ik_max_word",
          "search_analyzer": "ik_max_word"
        },
        "fieldname": {
          "type": "text",
          "analyzer": "ik_max_word",
          "search_analyzer": "ik_max_word"
        }
      }
    }
  }
}'

Document

#插入
curl -X PUT 'localhost:9200/indexname/typename/id' -d '
{
  "fieldname": "field1",
  "fieldname": "field2",
  "fieldname": "field3"
}' 
#查看
curl 'localhost:9200/indexname/typename/id'
#删除
curl -X DELETE 'localhost:9200/indexname/typename/id'
#更新,我们只需要用相同的id再插入一次
curl -X PUT 'localhost:9200/indexname/typename/id' -d '
{
  "fieldname": "field4",
  "fieldname": "field5",
  "fieldname": "field6"
}' 
#查询所有记录,pretty是否格式化输出
curl 'localhost:9200/indexname/typename/_search?pretty=true'

JavaAPI

首先添加Maven依赖

#要与ES的版本一致
<dependency>
     <groupId>org.elasticsearch.client</groupId>
     <artifactId>elasticsearch-rest-high-level-client</artifactId>
     <version>6.2.3</version>
</dependency>

获取Client

public class InitESClient {
    private static RestHighLevelClient client = null;

    /**
     * 初始化Client
     *
     * @return
     */
    public static RestHighLevelClient init() throws Exception {
        if (client == null) {
            synchronized (InitESClient.class) {
                if (client == null) {
                    //获取IP,这个List里放着ES的IP地址
                    List<String> esIpList = ConfigUtils.ES_IP_LIST;
                    int size = esIpList.size();
                    if (size < 1) {
                        throw new Exception("es.ip is not configed,please check application.conf");
                    }
                    HttpHost[] httpHosts = new HttpHost[size];
                    for (int i = 0; i < size; i++) {
                        httpHosts[i] = new HttpHost(esIpList.get(i), 9200, "http");
                    }
                    client = new RestHighLevelClient(
                            RestClient.builder(httpHosts)
                    );
                }
            }
        }
        return client;
    }
}

创建Index和Type

//设置
Settings setting = Settings.builder()
       //分片数
       .put("index.number_of_shards", 5)
       //副本数
       .put("index.number_of_replicas", 3)
       //默认分词器
       .put("analysis.analyzer.default.tokenizer","ik_smart")
       .build();

//创建Index
CreateIndexRequest requestC = new CreateIndexRequest("indexname", setting);
//设置accounts表结构
requestC.mapping("typename", "建表json", XContentType.JSON);
//建表
CreateIndexResponse createIndexResponse = client.indices().create(requestC);

Document

批量插入

//获取client
RestHighLevelClient client = InitESClient.init();
//批量处理
BulkRequest request = new BulkRequest();
//存放内容
Map<String, String> map = new HashMap<>();
map.put("xxx","xxx");
//入库10条数据
for (int i = 0; i < 10; i++) {
    //增加插入请求,自动给定id
    request.add(new IndexRequest("indexname", "typename").source(map));
    //手动给定id
    //request.add(new IndexRequest("indexname", "typename","id").source(map));
}
//获取响应
BulkResponse bulk = client.bulk(request);

批量删除

//获取client
RestHighLevelClient client = InitESClient.init();
//批量处理
BulkRequest request = new BulkRequest();
//存放删除ID
ArrayList<String> ids = new ArrayList<>();
ids .add("B8PY8GwBnQxj8ZZg3hEN");
ids .add("AcPY8GwBnQxj8ZZg3hEN");
//批量删除
for (String id : ids ) {
    requestDelete.add(new DeleteRequest("indexname", "typename", id));
}
//执行删除操作
BulkResponse bulkDelete = client.bulk(requestDelete);

批量查询

//获取client
RestHighLevelClient client = InitESClient.init();
//获取对应A表内容
MultiGetRequest requestA = new MultiGetRequest();
//存放查询ID
ArrayList<String> ids = new ArrayList<>();
ids .add("B8PY8GwBnQxj8ZZg3hEN");
ids .add("AcPY8GwBnQxj8ZZg3hEN");
//查询请求
for (String id : ids ) {
    requestA.add("indexname", "typename", id);
}
//查询
MultiGetResponse multiGetItemAResponses = client.multiGet(requestA);
//获取查询结果
MultiGetItemResponse[] responsesA = multiGetItemAResponses.getResponses();
for (int i = 0; i < responsesA.length; i++) {
    MultiGetItemResponse responseA = responsesA[i];  
    //获取Source
    Map<String, Object> sourceAMap = responseA.getResponse().getSourceAsMap();
}

matchQuery

//目标表的字段
String[] typeFileds = {"name","title","desc"};
//B表的字段
String[] values = {"Lee","book","reading books"};
//权重
float[] weights = {0.5F, 0.2F, 0.2F};
SearchRequest searchRequest = new SearchRequest(ConfigUtils.ES_B_TYPE);
SearchSourceBuilder searchBuilder = new SearchSourceBuilder();
BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
//添加匹配条件
for (int i1 = 0; i1 < typeFileds.length; i1++) {
    Map<String, Object> sourceAsMap = hitA.getSourceAsMap();
    boolQueryBuilder.should(new MatchQueryBuilder(typeFileds [i1], 
        values[i1]))
            //设置权重,这个值最好在1-10之间
            .boost(weights[i1]);
}
//设置最小匹配数,表示name、title、desc三个条件最少匹配几条
boolQueryBuilder.minimumShouldMatch(ConfigUtils.ES_MINIMUMSHOULDMATCH);
//加入布隆查询
searchBuilder.query(boolQueryBuilder);
//关闭查询source
searchBuilder.fetchSource(false);
//获取得分最高的前N条数据
searchBuilder.size(ConfigUtils.ES_RANK_NUM);
searchRequest.source(searchBuilder);
SearchResponse searchAResult = client.search(searchARequest);
//查询结果
SearchHits hitAS = searchAResult.getHits();

matchPhraseQuery和matchQuery的区别,我们用一个例子来说明:

"中华人民共和国成立70周年啦"

我们使用:"中华儿女" 这四个字去匹配,

matchQuery可以匹配得到,但是matchPhraseQuery却匹配不到,是因为matchPhraseQuery索要匹配的内容("中华儿女")必须全部包含在索引的字段中("中华人民共和国成立70周年啦"),因为其中缺少“儿女”两个字所以无法匹配。

同时我们可以在slop中指定中华儿女四个字的距离,这样这四个字不用挨在一起也可以查得到。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值