ElasticSearch搜索引擎的概要

1、写在前面的话:

  在电商公司已待了三年有余,这样运营下去的一个电商品台,多少还是有些东西值得学习,今天对ElasticSearch这一利器来一个学习和总结。更多的,是对ES的相关讯息生成一个自己的笔记,以后自己回顾也好,再次接触ES需要进行开发和运用,也有一个思路可以追寻,也会针对自己的疑惑有再次提点作用。

2、再说ES前,需要了解es的底层架构Lucene:

2.1,Lucene以json格式作为文件存储结构:一条json格式的字符串就是一个文档,与MongoDB一模一样。

{"id" : "23", "name" : "郭冠兰", "sex" : "Male", "age" : 25}

2.2,Lucene建立索引分词器的特性:以倒排序的方式实现文档索引,这里可以展开说明:

  倒排序,在lucene接收到一个json字符串文档时,分词器会将接收到的数据按关键字分解,分解后的结构是:[term key] [docid]

{"name" : "郭冠兰", "address" : "广东省广州市天河区"},{"name" : "冠兰", "address" : "广东省广州市天河区"}

分词后的结构是:

[冠兰][124]

[郭冠兰][123]

[广东省][123,124]

[广州市][123,124],

[天河区][123,124],

说明:123,124分别是接收到的字符串文档在lucene文件存储系统中的文档id,我们举例它分配到的id是123,124,id也可以自行设定,也可以lucene生成。但是最好是按顺序有规律的id生成规则,自行指定时。

参考这里有详细的说明,这涉及到lucene底层搜索排序的高级算法:基础介绍及索引原理分析后面提到id生成规则,docid压缩算法等等。

在分词过程中,可以定义字段是否进行分词,全局分词等操作,例如:

RESTful形式:

PUT /my_index
{
  "mappings": {
    "my_type": {
      "properties": {
        "status_code": { //字段名
          "type": "string",
          "index": "not_analyzed"	//非查询字段”不建索引index
        }
		"title": {
          "type": "string",
          "store": true 
        },
        "content": {
          "type": "string"
        }
      }
    }
  }
}

Java api形式:

private XContentBuilder getMapping(String type) throws Exception {
	XContentBuilder mappingBuilder = XContentFactory.jsonBuilder().startObject().startObject(type)
		.startObject("_all").field("enabled", false).endObject()
		.startObject("properties")
			.startObject("userName").field("type", "keyword").endObject()
			.startObject("age").field("type", "integer").endObject()
			.startObject("create_time").field("type", "date").field("format", "yyyy-MM-dd HH:mm:ss||yyyy-MM-dd").field("index", "not_analyzed")
			.field("include_in_all", false).endObject();	//不创建索引
		.endObject()
	.endObject().endObject();
	return mappingBuilder;
}

index的参数值:

· no: 不把此字段添加到索引中,也就是不建索引,此字段不可查询 
· not_analyzed:将字段的原始值放入索引中,作为一个独立的term,它是除string字段以外的所有字段的默认值。 
· analyzed:string字段的默认值,会先进行分析后,再把分析的term结果存入索引中。

 

3、ES的高效性原理:

es为何如此高效?为了提高查询效率,lucene在分词过程、存储数据,和索引结构中下了很多功夫。我自己不会总结,在网上查看了很多文章,发现很多精妙之处,此处查看这几篇文章了解:

时间序列数据库的秘密 (2)——索引 ,都是底层的算法,如果没有耐心,会看不懂,枯燥无味。

仔细看了之后深有体会,底层竟如是如此的算法,惊奇,巧妙,从此对算法有了很深深的好感,果然应了那句话,大神都是玩算法,渣渣讨论代码。

4、ES的查询:

lucene分词,默认情况下是对所有字段创建倒排索引的(动态mapping解析出来为数字类型、布尔类型的字段除外),某个字段是否生成倒排索引是由字段的index属性控制的,可查看上面的Java代码,在第一次创建索引库的时候进行设置,之后往这加入文档的时便遵照这设置进行建索引。

//根据字段,索引查询    
private BoolQueryBuilder convertParam(UserSearchParam param) {

    	BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
    	if (StringUtils.hasText(param.getUserName())) {
    	    boolQueryBuilder.must(QueryBuilders.termQuery("name", param.getName()));
    	}
    	if (param.getAge() != null) {
    	    boolQueryBuilder.must(QueryBuilders.rangeQuery("age").gt(param.getAge()));
    	}
    	if (StringUtils.hasText(param.getDescription())) {
    	    boolQueryBuilder.must(QueryBuilders.matchQuery("description", param.getDescription()));
    	}
    	return boolQueryBuilder;
    }

//创建索引
public boolean createIndex(String index, String type) {
    	XContentBuilder mappingBuilder;
    	try {
    	    mappingBuilder = this.getMapping(type);
    	} catch (Exception e) {
    	    logger.error("创建Mapping 异常");
    	    return false;
    	}
    	Settings settings = Settings.builder().build();
    	IndicesAdminClient adminClient = client.admin().indices();
    	CreateIndexRequestBuilder builder = adminClient.prepareCreate(index);
    	builder.setSettings(settings);
    	CreateIndexResponse response = builder.addMapping(type, mappingBuilder).get();
    	
    	return response.isAcknowledged();
    }

//创建索引的Mapping信息  注意声明的roles为nested类型
private XContentBuilder getMapping(String type) throws Exception {
	XContentBuilder mappingBuilder = XContentFactory.jsonBuilder().startObject().startObject(type)
		.startObject("_all").field("enabled", false).endObject()
		.startObject("properties")
			.startObject("userName").field("type", "keyword").endObject()
			.startObject("age").field("type", "integer").endObject()		
			.startObject("create_time").field("type", "date").field("format", "yyyy-MM-dd HH:mm:ss||yyyy-MM-dd").field("index", "not_analyzed").field("include_in_all", false).endObject();
		.endObject()
	.endObject().endObject();
	return mappingBuilder;
}

有一点需要注意,es在默认情况下,是针对所有字段进行索引,却也可以针对单个字段进行索引查询:

//例如查询一个商品的货号字段Java代码
//货号
if(!StringUtils.isEmpty(productViewParam.getGoodsNo())){
	boolQueryBuilder.must(QueryBuilders.termQuery("goodsNo", productViewParam.getGoodsNo()));
}
//单个匹配,搜索goodsNo为某个值的文档

存储在es上的文档,除了各个字段外,也额外存在一个_all字段存储字段的所有值,并已空格隔开各个字段值:例如

该字段可开启和关闭,ES的各字段,查看更多字段含义。

4、结尾:

文章说的比较凌乱,思路不清晰,就是把网络上很多的知识拼接在一起,算是对自己的一个笔记和温习的思路吧,如果有兴致可以仔细读,对es有个了解。

感谢网络上很多大神,写了很多好文章,在此就引用,作为一个入口去查看。

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值