ElasticSearch基本使用

基本概念

​ ES是基于Lucene的搜索服务器,是一个分布式多用户的全文搜索引擎。

ES
cluster整个ES默认就是集群状态,整个集群是完整、互备的状态
node一个节点
shard分片。默认分5片,7.x版本默认分1片
index5.x的版本对应关系型数据库的database,6.x和7.x的版本对应关系型数据库中的表
type5.x的版本对应关系型数据库的表,6.x的版本只允许有一个,7.x的版本被废弃。
document对应关系型数据库的行
field对应关系型数据库的列

特点

天然分片、天然集群

​ ES 6.x的版本,分片shard默认为5片;ES 7.x的版本,shard默认为1片。

​ 一般一个分片的数据不要超过30G,10G以下的数据建议分1片。

天然索引

​ ES使用倒排索引,根据内容分词去匹配主键。

倒排索引

ES使用倒排索引的数据结构,有倒排索引就有正向索引。

正向索引使用的是文档的id去匹配文档,如果我们的数据量很大,我们要在海量数据中查找想要的数据,就要先进行全表扫描找出id对应的文档,再去文档中查找指定内容。

倒排索引是先对每个文档进行分词,提取关键字,建立关键字与文档间的关系。每个关键字都会对应多个文档,文档对应的越多,关键字和文档的相关程度(评分)越高。当我们查找时,会根据我们的关键字进行分词,将文档相关程度高的排在前面。

Restful API

PUT插入数据|document

格式:PUT index/type/id (这里的id非字段中的id,可以省略,如果省略会自动生成)

注意:

  • PUT是幂等性插入,即多次业务操作的结果是一致的
  • PUT更新数据时,会覆盖原有的document。
PUT movie0508/movie/1
{ "id":1,
  "name":"operation red sea",
  "doubanScore":8.5,
  "actorList":[  
{"id":1,"name":"zhang yi"},
{"id":2,"name":"hai qing"},
{"id":3,"name":"zhang han yu"}
]
}
PUT movie0508/movie/2
{
  "id":2,
  "name":"operation meigong river",
  "doubanScore":8.0,
  "actorList":[  
{"id":3,"name":"zhang han yu"}
]
}

PUT movie0508/movie/3
{
  "id":3,
  "name":"incident red sea",
  "doubanScore":5.0,
  "actorList":[  
{"id":4,"name":"zhang chen"}
]
}

POST插入数据|document

格式:POST index/type/id (这里的id非字段中的id,可以省略,如果省略会自动生成)

注意:

  • POST是非幂等性插入。
  • POST更新数据时,可以只更新指定字段的内容。
POST movie0508/movie
{
  "id":"3",
  "name":"Monkey King Reborn",
  "score":5.5,
  "actorList":
  [
    {"id":1,"name":"bian jiang"},
    {"id":2,"name":"zhang lei"}  
  ]
}

DELETE删除单个文档

格式:DELETE index/type/id(此id非字段中的id值,是用来分片的id)

注意:

  • ES中删除文档并不会真正的删除,而是将文档的数据标记为“已过期”,也会占用磁盘空间。
DELETE movie0508/movie/3

DELETE删除index

格式:DELETE index

注意:

  • ES中删除索引是真正的删除,不会进行标记。
DELETE movie0508

POST修改数据

格式:POST index/type/id/_update{ “doc”:{ “字段名”:值 } }

​ PUT index/type/id{数据}

注意:

  • PUT修改数据时会覆盖原来的document。
  • POST可以修改指定字段的数据,其他的数据不变。
POST movie0508/movie/2/_update
{
  "doc":{
    "score":4.6
  }
}

GET查询

查询指定index的数据

格式:GET index/type/_search(type可以省略)

GET movie0508/movie/_search

查询指定id的数据

格式:GET index/type/id

GET movie0508/movie/3

按条件查询(全部)

格式:

GET index/type/_search

{

“query”:{

“match_all”:{}

}

}

GET movie0508/movie/_search
{
  "query": {
    "match_all": {}
  }
}

按分词查询

按照分词查询会对匹配字段的值进行分词,按照分词匹配相关度,按照相关度从大到小排序。

格式:

GET index/type/_search
{
"query": {
"match": {
"字段": "值"
}
}
}

GET movie0508/movie/_search
{
  "query": {
    "match": {
      "name": "sea"
    }
  }
}

按分词属性查询

GET movie0508/movie/_search
{
  "query": {
    "match": {
      "actorList.name": "han"
    }
  }
}

查询指定词(等值查询)

格式:

GET index/type/_search
{
"query": {
"term": {
"keyword类型的字段": {
"value": "要查询的值"
}
}
}
}

GET movie0508/movie/_search
{
  "query": {
    "term": {
      "name.keyword": {
        "value": "operation red sea"
      }
    }
  }
}

按短语(一组词)查询

GET index/type/_search
{
"query": {
"match_phrase": {
"字段": "值"
}
}
}

GET movie0508/movie/_search
{
  "query": {
    "match_phrase": {
      "name": "red sea"
    }
  }
}

模糊|容错查询

当要查询的单词和词库中一个单词都无法匹配,可以返回相差不多的单词和一定的评分。

GET index/type/_search
{
"query": {
"fuzzy": {
"字段": "值"
}
}
}

GET movie0508/movie/_search
{
  "query": {
    "fuzzy": {
      "name": "rad"
    }
  }
}

查询后过滤

GET index/type/_search

{

“query”: {

“match”: { “字段”: “值” }

},

“post_filter”: {

“term”: {

“字段”: [“值1”, “值2”]

}

}

}

GET movie0508/movie/_search
{
  "query": {
    "match": {
      "name": "red"
    }
  },
  "post_filter": {
    "term": {
      "id": 3
    }
  }
}

边查询边过滤(推荐使用)

GET index/type/_search

{

“query”:{

“bool”: {

“filter”: {

“term”: {

“字段”:"值"

}

},

“must”: [

“match”:{

“字段”:"值"

}

]

}

}

}

GET movie0508/movie/_search
{
  "query": {
    "bool": {
      "filter": {
        "term": {
          "name": "red"
        }
      },
      "must": [
        {
          "match": {
            "actorList.name": "zhang han yu"
          }
        }
      ]
    }
  }
}

按范围过滤

GET index/type/_search

{

“query”: {

“bool”: {

“filter”: {

“range”: {

“字段”:{

​ # gte:大于等于 gt:大于

“gte|gt”: 值,

“lte|lt”: 值

}

}

}

}

}

}

GET movie0508/movie/_search
{
  "query": {
    "bool": {
      "filter": {
        "range": {
          "doubanScore": {
            "gte": 5,
            "lte": 6
          }
        }
      }
    }
  }
}

排序

GET index/type/_search
{
"query": {
"match": {
"字段": "值"
}
},
"sort": [
{
"字段": {
"order": “desc”|"asc"
}
}
]
}

GET movie0508/movie/_search
{
  "query": {
    "match": {
      "name": "sea"
    }
  },
  "sort": [
    {
      "doubanScore": {
        "order": "desc"
      }
    }
  ]
}

分页查询

GET index/type/_search
{
"query": {
"match_all": {}
},
"from": 起始条数,
"size": 每页条数
}

GET movie0508/movie/_search
{
  "query": {
    "match_all": {}
  },
  "from": 0,
  "size": 2
}

指定查询字段

GET index/type/_search
{
“query”: {
“match_all”: {}
},
“_source”: [“字段1”,“字段2”]

}

GET movie0508/movie/_search
{
  "query": {
    "match_all": {}
  }, 
  "_source": ["actorList.name","name"]
}

高亮

GET index/type/_search
{
“query”: {
“match”: {
“字段”: “值”
}
},
“highlight”: {
“fields”: {“字段”:{}}
}
}

GET movie0508/movie/_search
{
 "query": {
   "match": {
     "name": "sea"
   }
 },
 "highlight": {
   "fields": {"name":{}}
 }
}

分组

GET index/type/_search
{
"aggs": {
"分组后的别名": {
"terms": {
"field": “分组字段.keyword”,
"size": 显示的条数
}
}
}
}

注意:

​ 分组字段必须是keyword类型,即必须是等值,不能分词。默认按照count聚合。

GET movie0508/movie/_search
{
 "aggs": {
   "group_by_act": {
     "terms": {
       "field": "actorList.name.keyword",
       "size": 10
     }
   }
 }
}

聚合

GET index/type/_search
{
"aggs": {
"分组别名1": {
"terms": {
"field": “分组字段.keyword”,
"order": {
"分组别名2": "desc|asc"
}
},
"aggs": {
"分组别名2": {
"聚合类型": {
"field": "聚合字段"
}
}
}
}
}
}

GET movie0508/movie/_search
{
 "aggs": {
   "group_act": {
     "terms": {
       "field": "actorList.name.keyword",
       "order": {
         "avg_score": "desc"
       }
     },
     "aggs": {
       "avg_score": {
         "avg": {
           "field": "doubanScore"
         }
       }
     }
   }
 }
}

定义mapping

​ 如果没有mapping,ES默认会根据数据自动推断字段的类型。

- true|false => bool
- 1 => long
- 1.1 => float
- "a" => text + keyword
- "2021-05-11" => date

​ 对于有些数据,我们只需要等值检索,不需要分词,那么只存储为keyword类型即可。

注意:

mapping只能对不包含数据的字段进行定义。

基于中文分词创建mapping

PUT index

{

​ “mappings”: {

​ “type名称”:{

​ “properties”: {

​ “字段”:{

​ “type(固定)”: “类型”,

​ “analyzer”: “分词器类型”

​ }

​ }

​ }

​ }

}

PUT movie0511_chi
{
  "mappings": {
    "movie": {
      "properties": {
        "id": {
          "type": "long"
        },
        "name": {
          "type": "text",
          "analyzer": "ik_smart"
        },
        "doubanScore": {
          "type": "double"
        },
        "actorList": {
          "properties": {
            "id": {
              "type": "long"
            },
            "name": {
              "type": "keyword"
            }
          }
        }
      }
    }
  }
}

索引别名 _aliases

  • 一个索引可以有多个别名,一个别名可以对应多个索引。
  • 别名可以灵活的对索引进行分组,根据分组进行统计。
  • 创建索引的子集,筛选符合某条件的数据。
  • 索引别名的更换是原子性的,可以在运行的集群中无缝切换。

创建索引同时指定别名

PUT index

{

“aliases”: {

“别名”:{}

},

“mappings”: {

}

}

PUT movie0511_chi
{
  "aliases": {
    "movie05-query": {}
  },
  "mappings": {
    "movie": {
      "properties": {
        "id":{
          "type": "long"
        },
        "name":{
          "analyzer":"ik_smart",
          "type": "text"
        },
        "doubanScore":{
          "type":"double"
        },
        "actorList":{
          "properties":{
            "id":{
              "type":"long"
            },
            "name":{
              "type":"keyword"
            }
          }
        }
      }
    }
  }
}

已存在索引添加别名

POST _aliases
{
"actions": [
{
"add": {
"index": “索引名”,
"alias": "别名"
}
}
]
}

POST _aliases
{
  "actions": [
    {
      "add": {
        "index": "movie0511_chi",
        "alias": "movie_chi-query"
      }
    }
  ]
}

过滤,创建子集

POST _aliases
{
  "actions": [
    {
      "add": {
        "index": "movie0508",
        "alias": "movie-",
        "filter": {
          "term": {
            "actorList.name.keyword": "zhang han yu"
          }
        }
      }
    }
  ]
}

按别名查询

GET 别名/_search

GET movie_chi-query/_search

删除别名

POST _aliases
{
"actions": [
{
"remove": {
"index": “索引名”,
"alias": "要删除的别名"
}
}
]
}

POST _aliases
{
  "actions": [
    {
      "remove": {
        "index": "movie0511_chi",
        "alias": "movie_chi-query"
      }
    }
  ]
}

别名无缝切换

POST _aliases
{
“actions”: [
{
“remove”: {
“index”: “索引1”,
“alias”: “别名”
}
},
{
“add”: {
“index”: “索引2”,
“alias”: “别名”
}
}
]
}

POST _aliases
{
  "actions": [
    {
      "remove": {
        "index": "movie0511_chi",
        "alias": "movie_chi-query"
      }
    },
    {
      "add": {
        "index": "movie0508",
        "alias": "movie-query"
      }
    }
  ]
}

查询别名列表

GET _cat/aliases

索引模板

作用

​ 根据业务需求,创建一系列符合某些mappings和settings的模板,通过使用索引模板,可以使得索引具备可知的一致性。

​ 如果ES中shard特别多,使用模板创建索引可能会有延迟。如果延迟不能接受,那么使用脚本创建索引。

使用场景

索引分割

  • 根据时间间隔将一个业务索引分割为多个索引。比如:按照每天日期存储每日的数据。
  • 结构变化的灵活性。ES不允许对数据的结构进行修改,如果数据的结构发生变化,那么我们可以在下一个周期对结构进行改变。
  • 查询范围优化。查询时不会对全部时间周期的表进行扫描,只查询某个时间范围内的数据。

创建模板

- index_patterns表示index的匹配规则。
- {index}-query是索引别名,{index}就是匹配到的index名称。
PUT _template/template_movie
{
  "index_patterns": ["movie_test*"],                  
  "settings": {                                               
    "number_of_shards": 1
  },
  "aliases" : { 
    "{index}-query": {},
    "movie_test-query":{}
  },
  "mappings": {                                          
"_doc": {
      "properties": {
        "id": {
          "type": "keyword"
        },
        "movie_name": {
          "type": "text",
          "analyzer": "ik_smart"
        }
      }
    }
  }
}

Scala使用Java API操作ES

导入jest依赖

<dependency>
    <groupId>io.searchbox</groupId>
    <artifactId>jest</artifactId>
    <version>5.3.3</version>

</dependency>

<dependency>
    <groupId>net.java.dev.jna</groupId>
    <artifactId>jna</artifactId>
    <version>4.5.2</version>
</dependency>

<dependency>
    <groupId>org.codehaus.janino</groupId>
    <artifactId>commons-compiler</artifactId>
    <version>2.7.8</version>
</dependency>

<dependency>
    <groupId>org.elasticsearch</groupId>
    <artifactId>elasticsearch</artifactId>
    <version>2.4.6</version>
</dependency>

测试插入和查询

import io.searchbox.client.config.HttpClientConfig
import io.searchbox.client.{JestClient, JestClientFactory}
import io.searchbox.core.{Index, Search, SearchResult}
import java.util
import org.apache.lucene.queryparser.xml.builders.BooleanQueryBuilder
import org.elasticsearch.index.query.{BoolQueryBuilder, MatchQueryBuilder, QueryBuilders, TermQueryBuilder}
import org.elasticsearch.search.builder.SearchSourceBuilder
import org.elasticsearch.search.sort.SortOrder

object EsUtils {
    private var factor: JestClientFactory = null


    def getConn(): JestClient = {
        if (factor == null) {
            builder()
        }
        factor.getObject
    }

    //创建连接
    def builder() = {
        factor = new JestClientFactory
        factor.setHttpClientConfig(
            //ES连接地址
            new HttpClientConfig.Builder("http://hadoop102:9200")
                    //是否多线程
                    .multiThreaded(true)
                    //最大连接数量
                    .maxTotalConnection(20)
                    //连接超时时间
                    .connTimeout(10000)
                    //读取超时时间
                    .readTimeout(10000).build()
        )

    }

    //插入数据
    def insertIndex(): Unit = {
        val jestClient: JestClient = getConn()
        //Builder设计模式
        //参数必须是可以转换为Json格式的对象
        val index = new Index.Builder(movieTest(2, "蜘蛛侠"))
                .index("movie_test01")
                .`type`("_doc")
                .id("1001")
                .build()
        jestClient.execute(index)

        jestClient.close()
    }

    //查询数据
    def searchResult() = {
        val jestClient: JestClient = getConn()
        //直接查询
        val query = "{\n  \"query\": {\n    \"bool\": {\n      \"filter\": {\n        \"term\": {\n          \"actorList.name.keyword\": \"zhang han yu\"\n        }\n      },\n      \"must\": [\n        {\n          \"match\": {\n            \"name\": \"operation\"\n          }\n        }\n      ]\n    }\n  },\n  \"from\": 0,\n  \"size\": 20,\n  \"sort\": [\n    {\n      \"doubanScore\": {\n        \"order\": \"desc\"\n      }\n    }\n  ]\n}"
        //使用ES自带的API
        val searchBuilder = new SearchSourceBuilder()
        //将ES查询转换为API
        val booleanBuilder: BoolQueryBuilder = QueryBuilders.boolQuery()
        booleanBuilder.filter(new TermQueryBuilder("actorList.name.keyword","zhang han yu"))
        booleanBuilder.must(new MatchQueryBuilder("name","operation"))
        searchBuilder.from(0)
        searchBuilder.size(20)
        searchBuilder.sort("doubanScore",SortOrder.DESC)
        //API查询转换为字符串
        val query2: String = searchBuilder.toString

        val queryBuilder = new Search.Builder(query2)
                .addIndex("movie0508")
                .addType("movie")
                .build()
        val result = jestClient.execute(queryBuilder)
        //将结果封装为可以转化为json的对象,比如Map、样例类
        //Map必须是Java中的Map,因为使用的是java的API
        val hits: util.List[SearchResult#Hit[util.Map[String, Any], Void]] = result.getHits(classOf[util.Map[String,Any]])
        import scala.collection.JavaConversions._
        val res: List[util.Map[String, Any]] = hits.map(_.source).toList
        println(res.mkString("\n"))
        jestClient.close()
    }

    def main(args: Array[String]): Unit = {
        searchResult()
    }
}

case class movieTest(id: Int, name: String)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值