学习目标 索引管理 自定义分析器 地理坐标点
索引管理
Elasticsearch权威指南-索引管理 我们之前的index都是在创建document,让es自动帮我们创建index。现在我们来讲解如何手动创建index,以便更好适用我们的应用。
创建索引
代码语言:javascript复制put /my_index
{
"settings":{...any setting...},
"mappings":{
"type_one":{...any mappings...},
"type_one":{...any mappings...},
....
}
}
可以在config/elasticsearch.yml添加配置,设置静止自动创建index
action.auto_create_index:false
index有3个最重要的配置:设置主分片,设置复制分片,设置分析器
PUT /my_temp_index { "settings": { "number_of_shards" : 1, "number_of_replicas" : 0 } }
动态设置副本分片,主分片不能动态修改
PUT /my_temp_index/_settings { "number_of_replicas": 1 }
自定义分析器
代码语言:javascript复制我们知道分析器是由,字符过滤器,分词器,标记过滤器组成
例子:
1. 用 html_strip 字符过滤器去除所有的 HTML 标签
2. 将 & 替换成 and ,使用一个自定义的 mapping 字符过滤器
"char_filter": {
"&_to_and": {
"type": "mapping",
"mappings": ["&=> and "]
}
}
1. 使用 standard 分词器分割单词
2. 使用 lowercase 标记过滤器将词转为小写
3. 用 stop 标记过滤器去除一些自定义停用词。
"filter": {
"my_stopwords": {
"type": "stop",
"stopwords": ["the", "a"]
}
}
根据以上描述来将预定义好的分词器和过滤器组合成我们的分析器:
"analyzer": {
"my_analyzer": {
"type": "custom",
"char_filter": ["html_strip", "&_to_and"],
"tokenizer": "standard",
"filter": ["lowercase", "my_stopwords"]
}
}
一句话合并请求:
PUT /my_index
{
"settings": {
"analysis": {
"char_filter": {
"&_to_and": {
"type": "mapping",
"mappings": ["&=> and "]
}
},
"filter": {
"my_stopwords": {
"type": "stop",
"stopwords": ["the", "a"]
}
},
"analyzer": {
"my_analyzer": {
"type": "custom",
"char_filter": ["html_strip", "&_to_and"],
"tokenizer": "standard",
"filter": ["lowercase", "my_stopwords"]
}
}
}
}
}
字符过滤器是让字符串在被分词前变得更加“整洁”。例如 我们可以使用 html_strip 字符过滤器 来删除所有的 HTML 标签 一个分析器 必须 包含一个分词器。分词器将字符串分割成单独的词(terms)或标记 (tokens)。 standard 分析器使用 standard 分词器将字符串分割成单独的字词,删除 大部分标点符号, keyword 分词器输出和它接收到的相同的字符串,不做任何分词处理。 whitespace 分词器只通过空格来分割文本 标记过滤器可能修改,添加或删除标记。我们已经提过 lowercase 和 stop 标记过滤
日期检测
代码语言:javascript复制当 Elasticsearch 遇到一个新的字符串字段时,它会检测这个字段是否包含一个可识别的日 期,
比如 2014-01-01 。如果它看起来像一个日期,这个字段会被作为 date 类型添加,
否 则,它会被作为 string 类型添加。
但是实际上这个字段不是一个date类型,只是第一次见到这个字段的值是“2018-05-06”
但是可能第二次这个字段的值就变成了“aaaaaaa”,这显然不是一个日期,但为时已晚。
这个字段已经被添加为日期类型,这个 不合法的日期 将 引发异常。所以要禁止日期检测
PUT /my_index
{
"mappings": {
"my_type": {
"date_detection": false
}
}
}
地理坐标点 Elasticsearch 入门教程 – GEO位置搜索 Elasticsearch权威指南
代码语言:javascript复制地理坐标点是指用经纬度来表示地球表面的某一个位置。
可以用来计算两个地方的位置,可以用来判断是不是落在某个区域。
地理坐标点不能被动态映射(dynamic mapping)自动检测,
而是需要显式声明对应字段类型 为 geo_point
PUT /address
{
"mappings": {
"address":{
"properties": {
"name":{
"type": "text"
},
"location":{
"type": "geo_point"
}
}
}
}
}
PUT /address/address/3
{
"name": "zuipin",
"location": [118.18191647528275,24.486064774155608]
}
表示经纬度有3种表达方式
(1)以半角逗号分割的字符串形式 "lat,lon"
"location": "40.715, -74.011"
(2)数组形式表示 [lon,lat]
(3)明确以 lat 和 lon 作为属性的对象
"location": {"lat": 40.722, "lon": -73.989 }
地理坐标盒模型过滤器
代码语言:javascript复制geo_bounding_box
指定一个一个矩形,过滤掉不落在矩形里面的坐标点。
GET /address/address/_search
{
"query": {
"bool": {
"filter": {
"geo_bounding_box": {
"location": {
"top_left": {
"lat": 40.8,
"lon": -74.0
},
"bottom_right": {
"lat": 40.7,
"lon": -73.0
}
}
}
}
}
}
}
优化盒模型
盒模型我们可以建倒排索引来优化。
创建index时候就要指定<1>
"location": { "type": "geo_point", "lat_lon": true <1> }
在查询的时候<1>
GET /address/address/_search
{
"query": {
"bool": {
"filter": {
"type": "indexed", <1>
"geo_bounding_box": {
"location": {
"top_left": {
"lat": 40.8,
"lon": -74.0
},
"bottom_right": {
"lat": 40.7,
"lon": -73.0
}
}
}
}
}
}
}
地理位置距离过滤器
代码语言:javascript复制geo_distance
地理距离过滤器 ( geo_distance )以给定位置为圆心画一个圆,来找出那些位置落在其中的文档
GET /address/address/_search
{
"query": {
"bool": {
"filter": {
"geo_distance": {
"distance": "300m",
"distance_type": "arc",
"location": [118.17985653878976,24.4863137535666]
}
}
}
}
}
地理位置距离过滤器代价贵,es先通过构建一个边长为2倍距离的矩形,来围住圆形,过滤掉大部分不在矩形内的坐标点。
//
distance_type:arc、plane、sloppy_arc
arc:把地球当做球体来计算,精准度最好,但是性能较差
plane:地球当成是平坦的来计算,精准度较差,但是性能较好,赤道比较精准,往两级越来越不准,
用户真的会在意一个宾馆落在指定圆形区域数米之外了吗??
大部分实际应用场景中,使用精度较低但响应更快的 计算方式可能就挺好
sloppy_arc:是默认的方式,比arc快4~5倍,距离精度达99.9%。
地理距离区间过滤器
代码语言:javascript复制地理距离过滤器 ( geo_distance )和 地理距离区间过滤器(geo_distance_range )的唯一差别在
于后者是一个环状的,它会排除掉落在内圈中的那部分文档
5.x已经不支持
[geo_distance_range] queries are no longer supported for geo_