Elasticsearch入门教程

全文搜索属于最常见的需求,开源的 Elasticsearch是目前全文搜索引擎的首选。
它可以快速地储存、搜索和分析海量数据。维基百科、Stack Overflow、Github 都采用它。

什么是 Elasticsearch

Elastic 的底层是开源库Lucene。但是,你没法直接用Lucene,必须自己写代码去调用它的接口。Elastic 是 Lucene 的封装,提供了 REST API的操作接口,开箱即用。

安装

  • Elasticsearch 需要 Java 8 环境

1. Windows上运行ElasticSearch

下载安装包 elasticsearch-6.2.4.zip https://www.elastic.co/downloads/elasticsearch

解压压缩包,其目录结构如下:

从命令窗口运行位于bin文件夹中的elasticsearch.bat,可以使用CTRL + C停止或关闭它


见到xxxx started,那么就是启动完成了,打开浏览器输入http:\\localhost:9200http:\\127.0.0.1:9200,如果出现以下文本证明启动成功了。

{
  "name" : "ubH8NDf",  
  "cluster_name" : "elasticsearch",
  "cluster_uuid" : "sJfrIwlVRBmAArbWRLWyEA",  
  "version" : {
    "number" : "6.2.4",
    "build_hash" : "ccec39f",
    "build_date" : "2018-04-12T20:37:28.497551Z",
    "build_snapshot" : false,
    "lucene_version" : "7.2.1",
    "minimum_wire_compatibility_version" : "5.6.0",
    "minimum_index_compatibility_version" : "5.0.0"
  },
  "tagline" : "You Know, for Search"
}

默认情况下,Elastic 只允许本机访问,如果需要远程访问,可以修改 Elastic 安装目录的config/elasticsearch.yml文件,去掉network.host的注释,将它的值改成0.0.0.0,然后重新启动 Elastic。

network.host: 0.0.0.0

上面代码中,设成0.0.0.0让任何人都可以访问。线上服务不要这样设置,要设成具体的 IP。

集群搭建

  1. 准备好三个文件夹
  2. 修改配置文件:进入到其中某个节点文件中config文件夹中,打开elasticsearch.yml进行配置
  3. 具体的配置信息参考如下:
节点1的配置信息:  
http.cors.enabled: true #是否允许跨域
http.cors.allow-origin: "*"
cluster.name: my-esLearn   #集群名称,保证唯一  
node.name: node-1   #节点名称,必须不一样  
network.host: 10.118.16.83   #必须为本机的ip地址  
http.port: 9200   #服务端口号,在同一机器下必须不一样  
transport.tcpport: 9300   #集群间通信端口号,在同一机器下必须不一样  
#设置集群自动发现机器ip集合  
discovery.zen.ping.unicast.hosts: ["10.118.16.83:9300", "10.118.16.83:9301", "10.118.16.83:9302"]  

节点2的配置信息:  
http.cors.enabled: true  #是否允许跨域
http.cors.allow-origin: "*"
cluster.name: my-esLearn   #集群名称,保证唯一  
node.name: node-2   #节点名称,必须不一样  
network.host: 10.118.16.83   #必须为本机的ip地址  
http.port: 9201   #服务端口号,在同一机器下必须不一样  
transport.tcpport: 9301   #集群间通信端口号,在同一机器下必须不一样  
#设置集群自动发现机器ip集合  
discovery.zen.ping.unicast.hosts: ["10.118.16.83:9300", "10.118.16.83:9301", "10.118.16.83:9302"]  

节点3的配置信息:  
http.cors.enabled: true #是否允许跨域
http.cors.allow-origin: "*"
cluster.name: my-esLearn   #集群名称,保证唯一  
node.name: node-3   #节点名称,必须不一样  
network.host: 10.118.16.83   #必须为本机的ip地址  
http.port: 9202   #服务端口号,在同一机器下必须不一样  
transport.tcpport: 9302   #集群间通信端口号,在同一机器下必须不一样  
#设置集群自动发现机器ip集合  
discovery.zen.ping.unicast.hosts: ["10.118.16.83:9300", "10.118.16.83:9301", "10.118.16.83:9302"] `

elasticsearch-head的搭建

解压已经下载 elasticsearch-head-master.zip,同时确认本机已经安装好nodejs,cmd->node -v确认nodejs是否安全成功。

解压压缩包,切换到elasticsearch-head-master已解压好的文件夹下。

c:\elasticsearch-head-master>npm install
c:\elasticsearch-head-master>npm start

用浏览器打开,http://10.118.16.83:9100/, 只要出现下图界面就证明成功了。

基本概念

Index

Elastic 会索引所有字段,经过处理后写入一个反向索引(Inverted Index)。查找数据的时候,直接查找该索引。
所以,Elastic 数据管理的顶层单位就叫做 Index(索引)。它是单个数据库的同义词。每个 Index (即数据库)的名字必须是小写。
下面的命令可以查看当前节点的所有 Index

$ curl -X GET 'http://10.118.16.83:9200/_cat/indices?v'

Document

Index 里面单条的记录称为 Document(文档)。许多条 Document 构成了一个 Index。
Document 使用 JSON 格式表示,下面是一个例子。

{
  "user": "张三",
  "title": "工程师",
  "desc": "数据库管理"
}

同一个 Index 里面的 Document,不要求有相同的结构(scheme),但是最好保持相同,这样有利于提高搜索效率。

数据操作

新增

向指定的 /Index/Type 发送 PUT 请求,就可以在 Index 里面新增一条记录。

$ curl -H "Content-Type:application/json" -X PUT '10.118.16.83:9200/accounts/person/1' -d '
{
  "user": "张三",
  "title": "工程师",
  "desc": "数据库管理"
}'

返回

{
  "_index":"accounts",
  "_type":"person",
  "_id":"1",
  "_version":1,
  "result":"created",
  "_shards":{"total":2,"successful":1,"failed":0},
  "created":true
}

若不指定id, 则改为Post请求 。id字段就是一个随机字符串。

更新

更新记录就是使用 PUT 请求,重新发送一次数据。

$ curl -H "Content-Type:application/json" -X PUT '10.118.16.83:9200/accounts/person/1' -d '
{
    "user" : "张三",
    "title" : "工程师",
    "desc" : "数据库管理,软件开发"
}' 

{
  "_index":"accounts",
  "_type":"person",
  "_id":"1",
  "_version":2,
  "result":"updated",
  "_shards":{"total":2,"successful":1,"failed":0},
  "created":false
}

记录的 Id 没变,但是版本(version)从1变成2,操作类型(result)从created变成updated,created字段变成false,因为这次不是新建记录

删除

删除记录就是发出 DELETE 请求

$ curl -X DELETE '10.118.16.83:9200/accounts/person/1'

数据查询

返回所有记录

使用 GET 方法,直接请求/Index/Type/_search,就会返回所有记录。

$ curl '10.118.16.83:9200/accounts/person/_search'

{
  "took":2,
  "timed_out":false,
  "_shards":{"total":5,"successful":5,"failed":0},
  "hits":{
    "total":2,
    "max_score":1.0,
    "hits":[
      {
        "_index":"accounts",
        "_type":"person",
        "_id":"AV3qGfrC6jMbsbXb6k1p",
        "_score":1.0,
        "_source": {
          "user": "李四",
          "title": "工程师",
          "desc": "系统管理"
        }
      },
      {
        "_index":"accounts",
        "_type":"person",
        "_id":"1",
        "_score":1.0,
        "_source": {
          "user" : "张三",
          "title" : "工程师",
          "desc" : "数据库管理,软件开发"
        }
      }
    ]
  }
}

上面代码中,返回结果的 took字段表示该操作的耗时(单位为毫秒),timed_out字段表示是否超时,hits字段表示命中的记录,里面子字段的含义如下。
total:返回记录数,本例是2条。
max_score:最高的匹配程度,本例是1.0。
hits:返回的记录组成的数组。
返回的记录中,每条记录都有一个_score字段,表示匹配的程序,默认是按照这个字段降序排列。

全文搜索

Elastic 的查询非常特别,使用自己的查询语法,要求 GET 请求带有数据体。

$ curl -H "Content-Type:application/json" '10.118.16.83:9200/accounts/person/_search'  -d '
{
  "query" : { "match" : { "desc" : "软件" }}
}'

Elastic 默认一次返回10条结果,可以通过size字段改变这个设置。还可以通过from字段,指定位移。

$ curl '10.118.16.83:9200/accounts/person/_search'  -d '
{
  "query" : { "match" : { "desc" : "管理" }},
  "from": 1,
  "size": 1
}'

逻辑运算

如果有多个搜索关键字, Elastic 认为它们是or关系。

$ curl -H "Content-Type:application/json" '10.118.16.83:9200/accounts/person/_search'  -d '
{
  "query" : { "match" : { "desc" : "软件 系统" }}
}'

如果要执行多个关键词的and搜索,必须使用布尔查询。

$ curl -H "Content-Type:application/json" '10.118.16.83:9200/accounts/person/_search'  -d '
{
  "query": {
    "bool": {
      "must": [
        { "match": { "desc": "软件" } },
        { "match": { "desc": "系统" } }
      ]
    }
  }
}'

由于查询还有很多种,请自行查阅相关资料,这里就不一一列出。

中文分词设置

安装分词插件

注意:安装对应版本的插件。
下载插件https://github.com/medcl/elasticsearch-analysis-ik/releases

使用 IK Analysis

要使用 IK Analysis,需要在文档类里面,指定相应的分词器。

ik_max_word 和 ik_smart 区别
ik_max_word: 会将文本做最细粒度的拆分,比如会将“中华人民共和国国歌”拆分为“中华人民共和国,中华人民,中华,华人,人民共和国,人民,人,民,共和国,共和,和,国国,国歌”,会穷尽各种可能的组合;

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

具体使用可参考https://github.com/medcl/elasticsearch-analysis-ik

public void highlighter() throws UnknownHostException {
    String preTags = "<strong>";  
    String postTags = "</strong>"; 
    HighlightBuilder highlightBuilder = new HighlightBuilder(); 
    highlightBuilder.preTags(preTags);//设置前缀  
    highlightBuilder.postTags(postTags);//设置后缀  
    highlightBuilder.field("content");

    SearchResponse response = client.prepareSearch("msg")
            .setTypes("tweet")
            .setSearchType(SearchType.DFS_QUERY_THEN_FETCH)
            .setQuery(QueryBuilders.matchQuery("content", "中国"))
            .highlighter(highlightBuilder)
            .setFrom(0).setSize(60).setExplain(true)
            .get();

    logger.info("search response is:total=[{}]",response.getHits().getTotalHits());
    SearchHits hits = response.getHits();
    for (SearchHit hit : hits) {
        logger.info("{} -- {} -- {}", hit.getId(), hit.getSourceAsString(), hit.getHighlightFields());
    }

    SearchRequestBuilder builder = client.prepareSearch("msg")
            .setTypes("tweet")
            .setSearchType(SearchType.DFS_QUERY_THEN_FETCH)
            .setQuery(QueryBuilders.matchQuery("content", "中国"));

}

  

通过Java程序连接Elasticsearch

 需要注意的是,我们通过浏览器 http://10.118.16.83:9200 访问可以正常访问,这里需要知晓,9200端口是用于Http协议访问的,如果通过客户端访问需要通过9300端口才可以访问

pom.xml添加依赖

<!-- Elasticsearch核心依赖包 -->
    <dependency>
        <groupId>org.elasticsearch.client</groupId>
        <artifactId>transport</artifactId>
        <version>6.2.4</version>
    </dependency>
    <!-- 日志依赖 -->
    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-log4j12</artifactId>
        <version>1.7.21</version>
        <scope>test</scope>
    </dependency>
    <!-- https://mvnrepository.com/artifact/org.apache.logging.log4j/log4j-core -->
    <dependency>
        <groupId>org.apache.logging.log4j</groupId>
        <artifactId>log4j-core</artifactId>
        <version>2.8.2</version>
    </dependency>

单点

import java.net.InetAddress;
import java.net.UnknownHostException;

import org.elasticsearch.client.transport.TransportClient;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.transport.TransportAddress;
import org.elasticsearch.transport.client.PreBuiltTransportClient;
import org.junit.Test;

public class ElasticsearchTest1 {
    public static final String HOST = "127.0.0.1";

    public static final int PORT = 9200; //http请求的端口是9200,客户端是9300

    @SuppressWarnings("resource")
    @Test
    public void test1() throws UnknownHostException {
        TransportClient client = new PreBuiltTransportClient(Settings.EMPTY).addTransportAddress(
                new TransportAddress(InetAddress.getByName(HOST), PORT));
        System.out.println("Elasticssearch connect info:" + client.toString());
        client.close();
    }
}

  

集群

import java.io.IOException;
import java.net.InetAddress;
import java.net.UnknownHostException;

import org.elasticsearch.action.index.IndexResponse;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.action.search.SearchType;
import org.elasticsearch.client.transport.TransportClient;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.transport.TransportAddress;
import org.elasticsearch.common.xcontent.XContentFactory;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.transport.client.PreBuiltTransportClient;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class ElasticsearchTest2 {
    public static final String HOST = "10.118.16.83";

    public static final int PORT = 9300; //http请求的端口是9200,客户端是9300

    private TransportClient client = null;

    private Logger logger = LoggerFactory.getLogger(ElasticsearchTest2.class);

    public static final String CLUSTER_NAME = "my-esLearn"; //实例名称

    //1.设置集群名称:默认是elasticsearch,并设置client.transport.sniff为true,使客户端嗅探整个集群状态,把集群中的其他机器IP加入到客户端中  
    private static Settings settings = Settings.builder()
            .put("cluster.name",CLUSTER_NAME)  
            .put("client.transport.sniff", true)  
            .build();  

    /**
     * 获取客户端连接信息
     * @Title: getConnect
     * @author ld
     * @date 2018-05-03
     * @return void
     * @throws UnknownHostException
     */
    @SuppressWarnings("resource")
    @Before
    public void getConnect() throws UnknownHostException {
        client = new PreBuiltTransportClient(settings).addTransportAddress(
                new TransportAddress(InetAddress.getByName(HOST), PORT));
        logger.info("连接信息:" + client.toString());
    }

    @After
    public void closeConnect() {
        if (client != null) {
            client.close();
        }
    }

    @Test
    public void test1() throws UnknownHostException {
        logger.info("Elasticssearch connect info:" + client.toString());
    }

    @Test
    public void addIndex() throws IOException {
        IndexResponse response = client.prepareIndex("msg", "tweet", "2").setSource(
                XContentFactory.jsonBuilder()
                .startObject()
                .field("userName", "es")
                .field("msg", "Hello,Elasticsearch")
                .field("age", 14)
                .endObject()).get();
    }

    @Test
    public void search() {
        SearchResponse response = client.prepareSearch("msg")
                .setTypes("tweet")
                .setSearchType(SearchType.DFS_QUERY_THEN_FETCH)
                .setQuery(QueryBuilders.matchPhraseQuery("user_name", "es"))
                .setFrom(0).setSize(60).setExplain(true)
                .get();

        logger.info("search response is:total=[{}]",response.getHits().getTotalHits());
        SearchHits hits = response.getHits();
        for (SearchHit hit : hits) {
            logger.info(hit.getId());
            logger.info(hit.getSourceAsString());
        }
    }
}

mysql与elasticsearch同步

可参考elasticsearch与数据库同步工具Logstash-input-jdbc

猜你喜欢

转载自www.cnblogs.com/ld-swust/p/9034941.html