1 Elasticsearch索引相关概念
1.1 term(索引词)
可以通过term query进行准确搜索.
1.2 text(文本)
文本是一段普通的非结构化文字, 通常文本会被分析成多个Term, 存储在ES的索引库中.
文本字段一般需要先分析再存储, 查询文本中的关键词时, 需要根据搜索条件搜索出原文本.
1.3 analysis(分析)
分析是将文本转换为索引词的过程, 分析的结果依赖于分词器.
1.4 cluster(集群)
集群由一至多个节点组成, 对外提供索引和搜索服务. 一个节点只能加入到一个集群中.
ES做到了去中心化: 访问任一节点等价于访问整个集群.
同一网络中, 每个ES集群都要有唯一的名称用于区分, 默认的集群名称为"elasticsearch".
水平扩展时, 只需要将新增节点的集群名称设置为要扩容的集群名称, 该节点就会自动加入集群中.
1.6 shard(分片)
单台机器(节点)无法存储大量的索引数据, ES可以把一个完整的索引分成多个分片, 分布到不同的节点上, 从而构成分布式索引.
每个分片都是一个Lucene实例, 也就是说每个分片底层都有一个单独的Lucene提供独立的索引和检索服务, 它们可以托管在集群的任一节点上.
单个Lucene中存储的索引文档最大值为 lucene-5843, 极限是2147483519(=integer.max_value - 128) 个文档. 可使用_cat/shards API 监控分片的大小.
1.7 replica(副本)
ES支持为每个Shard创建多个副本, 相当于索引数据的冗余备份.
分片有Primary Shard(主分片)、Replica Shard(副本分片), 建立索引时, 系统会先将索引存储在主分片中, 然后再将主分片中的索引复制到不同的副本中.
1.8 river(数据源)
从其他存储方式 (如数据库) 中同步数据到ES的方法, 它是以插件方式存在的一个ES服务, 通过读取river中的数据并把它索引到ES中.
官方的river有CouchDB、RabbitMQ、Twitter、Wikipedia等.
1.9 index(索引) 表导入进去,每条数据就是一个文档,这个文档集合就是索引
1.10 type(类型)
type是index的逻辑分类, 在ES 6.x版本之前, 每个索引中可以定义一个或多个type, 而在6.X版本之后, 一个index中只能定义一个type.
一种type一般被定义为具有一组公共field的document, 比如对博客系统中的数据建立索引, 可以定义用户数据type, 博客数据type, 评论数据type, 也就是每个document都必须属于某一个具体的type, 也就是说每个document都有_type属性.
1.11 document(文档)
文档是存储在ES中的一个个JSON格式的字符串, 是ES索引中的最小数据单元, 由field(字段)构成.
一个document可以是一条商品分类数据, 一条订单数据, 例如:
# book document
{
"book_id": "1",
"book_name": "Thinking in Java(Java 编程思想)",
"book_desc": "Java学习者不得不看的经典书籍",
"book_price": 108.00,
"category_id": "5"
}
1.12 mapping(映射)
类似于关系数据库中的Table结构, 每个index都有一个映射: 定义索引中每个字段的类型.
所有文档在写进索引之前都会先进行分析, 如何对文本进行分词、哪些词条又会被过滤, 这类行为叫做映射(mapping).
映射可以提前定义, 也可以在第一次存储文档时自动识别. 一般由用户自己定义规则.
类似于Solr中schema.xml约束文件的作用.
1.13 field(字段)
字段可以是一个简单的值(如字符串、数字、日期), 也可以是一个数组, 还可以嵌套一个对象或多个对象.
字段类似于关系数据库中表数据的列, 每个字段都对应一个类型.
可以指定如何分析某一字段的值, 即对field指定分词器.
1.14 动态映射
是Elasticsearch的一个重要特性: 不需要提前创建iindex、定义mapping信息和type类型, 你可以 直接向ES中插入文档数据时, ES会根据每个新field可能的数据类型, 自动为其配置type等mapping信息, 这个过程就是动态映射(dynamic mapping).
1.15
ES的索引中, 各概念的关系为: Field --> Document --> Type --> Index, 索引结构图如下:
2. ES命令
2.1查看集群中的索引
# 查询API:
GET _cat/indices?v
2.2 删除index
删除索引需要指明索引名称、别名或通配符.
Elasticsearch支持同时删除多个索引, 或使用_all或通配符*删除全部索引.
删除示例:
DELETE address // 删除指定索引
DELETE index1,index2 // 删除多个索引
DELETE index_* // 按通配符删除以'index_'开头的索引
DELETE _all
2.3 打开/关闭index
(1) 操作说明:
① 可以打开一个已经打开/关闭的索引, 以最后一次操作为准;
② 可以关闭一个已经关闭/打开的索引, 以最后一次操作为准;
③ 关闭的索引只能查看index的配置信息, 不能对内部的索引数据进行读写操作.
(2) 操作示例:
// 可以使用_all打开或关闭全部索引, 也可使用通配符(*)配合操作
POST address/_close
POST address/_open
3.常见问题
3.1集群状态为什么是yellow?
① 当前只有一个Elasticsearch节点, 而且此时ES中只有一个Kibana内建的索引数据.
② ES为每个index默认分配5个primary shard和5个replica shard, 为了保证高可用, 它还要求primary shard和replica shard不能在同一个node上.
③ 当前服务中, Kibana内建的index是1个primary shard和1个replica shard, 由于只有1个node, 所以只有primary shard被分配和启动了, 而replica shard没有被成功分配(没有其他node可用).
4.检索
Query Filter(过滤检索)
1.过滤查询, 比如: 查询name中包含Java, 且price不大于80元的商品:
GET book_shop/it_book/_search
{
"query": {
"bool": {
"must": {
"match": {"name": "Java"} // name中含有Java
},
"filter": {
"range": {
"price": {"lte": 80.0} // 价格不大于80.0
}
}
}
}
}
Phrase Search(短语检索)
Phrase Search不会对检索串进行分词处理, 只有一个文档的对应field中包含与检索文本完全一致的内容, 该文档才算匹配检索条件, 也才能作为结果返回 —— 可以理解为全文检索场景下的部分精确匹配.
2. 精确查询desc中包含"Java图书"的文档:
GET book_shop/it_book/_search
{
"query": {
"match_phrase": {
"desc": "Java图书"
}
},
"_source": ["name", "desc"]
}
3. 数值范围查询
需求: 查询商品中40 <= price <= 80的文档:
GET book_shop/_search
{
"query": {
"range": {
"price": {
"gte": 40,
"lte": 80,
"boost": 2.0 // 设置得分的权重值(提升值), 默认是1.0
}
}
}
}
4 时间范围查询
需求: 查询网站中最近一天发布的博客:
GET website/_search
{
"query": {
"range": {
"post_date": {
"gte": "now-1d/d", // 当前时间的上一天/四舍五入到最近的一天
"lt": "now/d" // 当前时间, /四舍五入到最近的一天
}
}
}
}
5 Elasticsearch的高级检索语法 (包括term、prefix、wildcard、fuzzy、boost等)
5.1 term query - 索引词检索
5.1.1 term query - 不分词检索
term query: 把检索串当作一个整体来执行检索, 即不会对检索串分词.
term是完全匹配检索, 要用在不分词的字段上, 如果某个field在映射中被分词了, term检索将不起作用.
所以, 不分词的field, 要在mapping中设置为不分词.
—— ES 5.x之后, 为每个text类型的字段新增了名为keyword的子字段, 是不分词的, 默认保留256个字符.
—— 可以使用keyword字段进行term检索. 示例:
GET book_shop/_search
{
"query": {
"term": {
"name.keyword": "Java编程思想"
}
}
}
5.1.2 terms query - in检索
terms, 相当于多个term检索, 类似于SQL中in关键字的用法, 即在某些给定的数据中检索:
GET book_shop/_search
{
"query": {
"terms": {
"name.keyword": [
"Java编程思想", "Java并发编程的艺术"
]
}
}
}
5.2 prefix query - 前缀检索
prefix query, 就是前缀检索. 比如商品name中有多个以"Java"开头的document, 检索前缀"Java"时就能检索到所有以"Java"开头的文档.
—— 扫描所有倒排索引, 性能较差.
GET book_shop/_search
{
"query": {
"prefix": { "name": "java" }
}
}
5.3 wildcard query - 通配符检索
扫描所有倒排索引, 性能较差.
GET book_shop/_search
{
"query": {
"wildcard": { "name": "ja*" }
}
}
5.4 regexp query - 正则检索
扫描所有倒排索引, 性能较差.
GET book_shop/_search
{
"query": {
"regexp": { "name": "jav[a-z]*" }
}
}
5.5 fuzzy query - 纠错检索
fuzziness的默认值是2 —— 表示最多可以纠错两次.
说明: fuzziness的值太大, 将削弱检索条件的作用, 也就是说纠错次数太多, 就会导致限定检索结果的检索条件被改变, 失去了限定作用.
示例: 检索name中包含"Java"的文档, Java中错一个字母e:
GET book_shop/_search
{
"query": {
"match": {
"name": {
"query": "Jave",
"fuzziness": 1,
"operator": "and"
}
}
}
}
5.6 boost评分权重 - 控制文档的优先级别
通过boost参数, 令满足某个条件的文档的得分更高, 从而使得其排名更靠前.
GET book_shop/_search
{
"query": {
"bool": {
"must": [
{ "match": { "name": "编程思想"} }
],
"should": [
{
"match": {
"name": {
"query": "艺术",
"boost": 2 // 提升评分权重,若为1则结果不同
}
}
}
]
}
}
}
5.7 复杂检索的使用范例
5.7.1 多条件过滤 - 包含
检索出版时间在2012-07之后, 且至少满足下述条件中一个的文档:
a. 名称(name)中包含"并发";
b. 描述(desc)中包含"java";
c. 出版社(publisher)名称中不包含"电子".
GET book_shop/_search
{
"query": {
"bool": {
"filter": { // 按时间过滤
"range": {
"date": {"gte": "2012-07"}
}
},
"should": [ // 可匹配, 可不匹配
{
"match": { "name": "并发" }
},
{
"bool": {
"must": { // 必须匹配
"match": { "desc": "java" }
},
"must_not": { // 不能匹配
"match": { "publisher": "电子" }
}
}
}
],
"minimum_should_match": 1 // 至少满足should中的一个条件
}
},
// 自定义排序
"sort": [
{ "price": { "order": "desc" } }
]
}
注意: 排序的字段最好是数字, 或日期, 因为字符串字段会被分词, ES会通过分词后的某个词去排序, 结果难以预测.
5.7.2 多条件拼接 - 包含+范围+排序
匹配检索: name中包含"java"却不包含"虚拟机";
范围检索: 价格大于50、小于80;
结果排序: 按照价格升序排序.
GET book_shop/_search
{
"query": {
"bool": {
"must": { // 必须匹配
"match": { "name": "java" }
},
"must_not": { // 必须不匹配
"match": { "name": "虚拟机" }
},
"filter": {
"range": {
"price": {
"gte": 40,
"lte": 80,
"boost": 2.0 // 设置得分的权重值(提升值), 默认是1.0
}
}
}
}
}
}
5.8 定制检索结果的排序规则
5.8.1 默认排序规则:
ES默认是按检索结果的分值(_score)降序排列的.
// 或通过constant_score过滤:
GET website/_search
{
"query": {
"constant_score": {
"filter": {
"term": {
"author_id": 5520 // 此时所有符合条件的_score都为1
}
}
}
}
}
5.8.2定制排序规则:
GET website/_search
{
"query": {
"constant_score": {
"filter": {
"term": {
"author_id": 5520
}
}
}
},
"sort": [
{
"post_date": { "order": "asc" }
}
]
}