ElasticSearch里面的路由功能介绍

在ElaticSearch里面,路由功能算是一个高级用法,大多数时候我们用的都是系统默认的路由功能,我们知道一个es索引可以分多个shard和每个shard又可以有多个replia,那么现在思考一个问题,我们添加进去的数据,是如何分布在各个shard上面的,而查询时候它是又怎么找到特定的数据呢。

默认情况下,索引数据的分片规则,是下面的公式:

shard_num = hash(_routing) % num_primary_shards

_routing字段的取值,默认是_id字段或者是_parent字段,这样的取值在hash之后再与有多少个shard的数量取模,最终得到这条数据应该在被分配在那个一个shard上,也就是说默认是基于hash的分片,保证在每个shard上数据量都近似平均,这样就不会出现负载不均衡的情况,然后在检索的时候,es默认会搜索所有shard上的数据,最后在master节点上汇聚在处理后,返回最终数据。

但有时候,我们会有另外一种情况,比如说存储一年的数据,如果按hash去索引,那就是分布非常均匀,这样的话无论查询什么数据都会去所有的shard上查询,如果数据量比较大,那么响应速度就比较慢,但这时,我们通过调查发现,一年12个月的数据本身分布并不均匀,有几个月的数据偏多,有几个月的数据偏少,理想情况下,数据偏少的月,查询性能应该更快,但如果是基于hash分片,那么我们并不能实现这种需求,因为hash分片,查询时候必须要命中所有shard之后,查询的结果才是准的,这样以来,每次查询都要扫描所有shard,比如我已经知道数据本身就是1月份的,那其实最好的情况下,只查询1月的数据就行,而不需要把一年的数据都扫描一遍,导致最终的结果就是慢的更慢,快的也慢,所以我们要针对性的做优化。

那么如何优化,其实思路也比较明确了,那就是按照月份分区,每一个月的数据都存在指定的分区中,如果是mysql那就是每个月份一张表,然后查询时候,直接查询对应月份的数据即可,在es和solr中原理也大致如此,唯一不同的地方在于es和solr都比较方便的支持了路由字段的设置而如果是数据库,则需要自己通过中间件的方式来搞定,比如说mycat等。

下面来介绍如何在es中使用路由字段,先看一个官网给的简单的例子:

PUT my_index/my_type/1?routing=user1&refresh=true 
{
  "title": "This is a document"
}

GET my_index/my_type/1?routing=user1

上面的代码中,指定了一个用户属性作为路由进行分区,然后查询的时候也必须指定路由。这一点需要注意 只要在索引时候加入路由字段,那么在以后的get,delete,update操作中都必须使用路由字段,否则会出现问题。

当然,路由字段本身,也是可以被查询的,看下面的代码:

GET my_index/_search
{
  "query": {
    "terms": {
      "_routing": [ "user1" ] 
    }
  }
}

除此之外,路由字段,也可以指定多个:

GET my_index/_search?routing=user1,user2 
{
  "query": {
    "match": {
      "title": "document"
    }
  }
}

如果指定多个用户属性,那么es会仅仅查询关联了这两个route属性的shard

如果加入路由字段之后,其他的操作(indexing,getting,deleting,updating)都必须指定路由字段,为了避免在使用时忘记添加 路由字段,导致同类数据会分布在多个shard上,这就违反了路由的原则,所以我们可以在mapping中 设置路由字段是必须字段,否则会提示错误:

PUT my_index2
{
  "mappings": {
    "my_type": {
      "_routing": {
        "required": true 
      }
    }
  }
}

PUT my_index2/my_type/1 
{
  "text": "No routing value provided"
}

缺失路由字段会抛出异常:

routing_missing_exception

还需要注意到是如果使用了路由字段,那么_id字段只能由用户保证唯一性,因为同一个id的数据,如果路由字段不一样 它是可以被存在到多个shard中的,而默认情况下是不会出现这种情况的。

最后接着说开头的例子,如果某个月数据量偏大,全部路由到一个shard里面依然性能有问题,es也提供了 同一个路由的字段的数据可以被分配到多个shard上,注意这是是多个shard,而不是所有shard,当然这里面有一定 限制一般情况下,不建议使用这种模式。

对solr中路由感兴趣的朋友,可以查看我以前写的文章:

http://qindongliang.iteye.com/blog/2312193

参考资料:

https://www.elastic.co/guide/en/elasticsearch/reference/current/mapping-routing-field.html



<think>我们正在解析Vue Router的代码示例。根据用户要求,需要逐行解释每个部分的功能和意义。 根据引用[1]中提供的代码片段:`const router = createRouter({ ... })`,这是一个典型的Vue Router路由配置。 我们将构建一个完整的Vue Router配置示例,并逐行解释。 注意:用户要求逐字解析,所以我们将对每一行代码进行详细说明。 下面是一个典型的Vue Router配置示例,我们将基于此进行解释: ```javascript import { createRouter, createWebHistory } from 'vue-router' const router = createRouter({ history: createWebHistory(import.meta.env.BASE_URL), routes: [ { path: '/', name: 'home', component: () => import('../views/HomeView.vue') }, { path: '/about', name: 'about', component: () => import('../views/AboutView.vue') } ] }) export default router ``` ### 逐行解析: 1. **`import { createRouter, createWebHistory } from 'vue-router'`** - 这行代码从`vue-router`库中导入两个函数:`createRouter`和`createWebHistory`。 - `createRouter`用于创建路由实例。 - `createWebHistory`用于创建基于HTML5 History API的历史记录模式,这种模式支持不带`#`的URL(即history模式)。 2. **`const router = createRouter({ ... })`** - 使用`createRouter`函数创建一个路由实例,并将其赋值给常量`router`。 - 该函数接受一个配置对象作为参数,配置对象包含两个主要属性:`history`和`routes`。 3. **`history: createWebHistory(import.meta.env.BASE_URL),`** - `history`属性定义了路由使用的历史记录模式。这里使用`createWebHistory`函数创建history模式。 - `import.meta.env.BASE_URL`是Vite环境变量,表示应用的基础路径。如果应用部署在子目录下,这个变量会被设置为子目录的路径(例如:`/my-app/`),这样路由会自动在该路径下工作。 4. **`routes: [ ... ]`** - `routes`属性是一个数组,用于定义应用程序的路由表。每个路由对象定义了一个路径(path)和对应的组件(component)等。 5. **`{ path: '/', name: 'home', component: () => import('../views/HomeView.vue') }`** - 这是一个路由对象,表示当用户访问根路径`'/'`时,会加载`HomeView.vue`组件。 - `path`:定义路由的路径。这里为根路径。 - `name`:给路由一个名称(可选),可以在代码中通过名称来引用这个路由(例如:在编程式导航中使用`router.push({ name: 'home' })`)。 - `component`:定义该路由对应的组件。这里使用了动态导入(`() => import('../views/HomeView.vue')`),这是一种代码分割技术,它使得该组件在需要时才会被加载(懒加载),从而优化应用的初始加载性能。 6. **`{ path: '/about', name: 'about', component: () => import('../views/AboutView.vue') }`** - 另一个路由对象,定义当用户访问`'/about'`路径时,加载`AboutView.vue`组件。 - 同样使用了动态导入实现懒加载。 7. **`export default router`** - 将创建的路由实例导出,以便在Vue应用实例中注册使用(通常在`main.js`或`main.ts`中导入并注册)。 ### 总结: - Vue Router的配置主要包括创建路由实例,并配置历史模式和路由表。 - 使用`createWebHistory`可以创建history模式的路由,它依赖于HTML5 History API,需要服务器支持以避免404问题。 - 路由表中的每个路由对象都映射一个路径到一个组件,并且可以设置名称以便于引用。 - 动态导入组件(懒加载)可以优化应用性能,将代码分割成多个块,按需加载。 ### 相关问题: 1. Vue Router支持哪些历史记录模式?它们之间有什么区别? 2. 如何实现路由懒加载?它有什么优势? 3. 在Vue Router中,如何定义嵌套路由? 4. 路由的`name`属性有什么作用?在哪些场景下会用到? 5. 如何处理Vue Router中的404页面(即匹配不到任何路由的情况)?</think>### Vue Router 代码逐行解析 以下是 Vue Router 的典型配置代码,我将逐行解释其功能和意义: ```javascript import { createRouter, createWebHistory } from 'vue-router' // [1] ``` 1. **`import { createRouter, createWebHistory } from 'vue-router'`** - 从 `vue-router` 库导入核心功能 - `createRouter`: 创建路由实例的工厂函数 - `createWebHistory`: 创建基于 HTML5 History API 的路由模式(支持干净的 URL,无 `#` 符号) --- ```javascript const router = createRouter({ // [2] ``` 2. **`const router = createRouter({ ... })`** - 创建路由实例并赋值给 `router` 常量 - 接受配置对象作为参数,包含路由的核心设置 --- ```javascript history: createWebHistory(import.meta.env.BASE_URL), // [3] ``` 3. **`history: createWebHistory(...)`** - 定义路由的历史模式(此处使用 HTML5 模式) - `import.meta.env.BASE_URL`: 获取 Vite 环境中的基础路径(适用于项目部署在子目录的情况) - 替代方案:`createWebHashHistory()` 使用 URL hash 模式(兼容旧浏览器) --- ```javascript routes: [ // [4] ``` 4. **`routes: [ ... ]`** - 定义路由映射表(路由配置的核心部分) - 数组结构,每个元素代表一个路由规则 --- ```javascript { path: '/', // [5] name: 'Home', // [6] component: () => import('../views/HomeView.vue') // [7] }, ``` 5. **`path: '/'`** - 定义 URL 路径匹配规则(此处匹配根路径) - 支持动态参数:如 `/user/:id` 6. **`name: 'Home'`** - 路由的唯一命名标识(可选但推荐) - 作用:编程式导航时可通过名称引用路由(如 `router.push({ name: 'Home' })`) - 避免硬编码 URL 路径,提高代码可维护性[^1] 7. **`component: () => import('../views/HomeView.vue')`** - 动态导入组件(代码分割/懒加载) - 使用 ES 动态导入语法 `() => import(...)` - 优势:按需加载组件,减少初始包体积,提升应用性能[^1][^3] --- ```javascript { path: '/about', name: 'About', component: () => import('../views/AboutView.vue'), children: [ // [8] { path: 'team', component: () => import('../views/TeamView.vue') } ] } ``` 8. **`children: [ ... ]`** - 定义嵌套路由(子路由) - 子路由路径会基于父路径拼接(此例中完整路径为 `/about/team`) - 需要在父组件的模板中添加 `<router-view>` 作为子路由出口 --- ```javascript ] }) ``` 9. **路由配置结束** - 关闭 `routes` 数组和 `createRouter` 配置对象 --- ```javascript export default router // [10] ``` 10. **`export default router`** - 导出路由实例 - 在 Vue 应用的主文件中导入并注册:`app.use(router)` ### 关键特性解析 1. **动态导入** - 使用 Webpack/Vite 的代码分割功能 - 路由访问时才会加载对应组件(减少首屏加载时间)[^1][^3] 2. **命名路由** - 提供路由的逻辑标识 - 解耦 URL 路径与代码引用关系[^1] 3. **路由模式** - `createWebHistory`: 需要服务器配置支持(避免 404 错误) - `createWebHashHistory`: 兼容性更好(URL 带 `#`) ### 相关问题 1. Vue Router 的导航守卫有哪些类型?它们分别在什么时机执行? 2. 如何在路由之间传递参数?比较 `params` 和 `query` 的区别? 3. Vue Router 4 相比 Vue Router 3 有哪些重大变更? 4. 如何实现路由级别的权限控制? 5. 路由懒加载的原理是什么?它如何优化应用性能?[^3] [^1]: 路由配置使用动态导入实现代码分割,提升应用性能 [^2]: 路由名称提供逻辑引用,避免硬编码路径 [^3]: 动态导入语法配合打包工具实现按需加载
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值