Elastic Stack介绍

https://blog.csdn.net/xb_workspace/article/details/85165070

什么是Elasticsearch

分布式高性能高可用可伸缩的的搜索和分析系统

1.什么是搜索

垂直搜索(站内搜索)
互联网的搜索:电商网站,招聘网站新闻网站各种APP
IT系统的搜索:OA软件,办公自动化软件,会议管理,日程管理,项目管理,员工管理

★搜索引擎原理

2.如果用数据库做搜索会怎么样

(1)每条记录的指定字段的文本,可能会很长,比如"商品描述"字段的长度,这时如果每次都要对每条记录的所有文本进行扫描,比较耗时.

(2)还不能将搜索词拆分开来,比如输入"海市楼",就搜索不出海市蜃楼,用数据库来实现搜索,性能较差.

3.什么是全文搜索和Lucene

(1)全文搜索,倒排索引
(2)Lucene就是一个jar包,里面包含了封装好的各种建立倒排索引,以及进行搜索的代码,包括各种算法.我们用Java开发的时候,引入Lucene jar,然后基于Lucene开发就可以了.用Lucene可以将已有的数据建立索引,Lucene会在本地磁盘给我们组织索引的数据结构

https://www.cnblogs.com/xiaobai1226/p/7652093.html

安装Elasticsearch

github搜索elasticsearch-rtf,这是elasticsearch中文发行版,针对中文集成了相关插件,方便新手学习测试.

下载完成后,打开压缩文件,在cmd中运行bin/elasticsearch.bat

然后在浏览器打开http://127.0.0.1:9200/

安装head和kibana

github搜索elasticsearch-head
head插件类似于管理数据库的Navicat,基于浏览器(一个前端管理界面)

下载完成后解压,按照如下步骤进行(npm可用cnpm代替)

git clone git://github.com/mobz/elasticsearch-head.git
cd elasticsearch-head
npm install

启动

npm run start

安装完成并启动后,我们在浏览器打开 http://127.0.0.1:9100/ ,但此时会发现显示未连接,这是由于ES默认安全策略,不允许安装其他第三方插件,我们需要配置elasticsearch与head互通.

在/config/elasticsearch.yml文件末尾添加一下内容

http.cors.enabled: true
http.cors.allow-origin: "*"

重启es和head,可以看到此时已经正常

kibana版本要和elasticsearch-rtf版本一致,所以我们直接百度搜索kibana5.1.1下载
下载完成后解压,然后cmd中执行/bin/下的kibana.bat,然后在浏览器中打开
http://127.0.0.1:5601/

快速启动Elasticsearch

Windows下建立如下bat文件

start D:\Python\Elasticsearch\elasticsearch-5.1.1\bin\elasticsearch.bat
start D:\Python\Elasticsearch\kibana-5.1.1-windows-x86\bin\kibana.bat@echo off
:: nodejs安装目录下的nodevars.bat
set nodevars = "C:\Program Files\nodejs\nodevars.bat"
:: 移动到需要启动的目录
cd d:/Python/Elasticsearch/elasticsearch-head-master
:: 启动项目
cmd /c %nodevars%&&npm run start@echo off
python D:\Python\ESsearch\manage.py runserver
cmd /k

Docker安装Elasticsearch

Elasticsearch概念

★倒排索引

https://www.cnblogs.com/zlslch/p/6440114.html

基本概念

集群:一个或多个节点组织在一起
节点:一个集群中的一台服务器
分片:索引划分为多份的能力,允许水平分割,扩展容量,多个分片响应请求
副本:分片的一份或多分,一个节点失败,其他节点顶上

Elasticsearch 与 MySQL 概念对比

Elasticsearch MySQL
index(索引) 数据库
type(类型)
documents(文档)
field(字段)

创建索引

方法一:浏览器kibana界面中dev tools中输入以下语句,(可以类比SQL语句)

PUT lagou
{"settings": {"index":{"number_of_shards":5,"number_of_replicas":1}}
}


之后我们可以在es界面看到已创建好的索引

方法二:也可以在es界面,手动点击创建索引

获取索引

获取lagou索引的settings

GET lagou/_settings

获取所有索引的settings,下面两条语句作用相同

GET _all/_settings
GET _settings


获取多个索引的settings

GET  .kibana,lagou/_settings

获取索引的信息,上面只是获取了settings

GET lagou

修改settings

我们可以修改number_of_replicas, 即副本的数量, 但是number_of_shards不能修改

PUT lagou/_settings
{"number_of_replicas":2
}

增加信息

  • job是type,我们需要定义
  • id也可以不定义,系统会自动添加
PUT lagou/job/1
{"title":"Python Cookbook","salary_min":15000,"city":"北京","company":{"name":"baidu","company_addr":"beijing"},"publish_data":"2019-01-01","comments":15
}


我们可以在http://127.0.0.1:9100/中查看我们增加的数据

如果我们只想查看source中部分内容,可以用下面的查询方式

修改数据

两种方式

  • PUT覆盖修改
  • POST增量修改

第一种方式

PUT lagou/job/1
{"title":"Python Cookbook","salary_min":15000,"city":"北京","company":{"name":"baidu","company_addr":"beijing"},"publish_data":"2019-01-01","comments":10
}
GET lagou/job/1


第二种方式

POST lagou/job/1/_update
{"doc":{"comments":20}
}
GET lagou/job/1

删除

1.删除文档

DELETE  lagou/job/1

2.不能删除type

DELETE lagou/job

3.删除索引

DELETE lagou

批量操作

为什么需要批量操作,因为之前的方式每次都建立HTTP请求,三次握手,比较耗时.
现在我们创建了如下图的索引以及类型

如果要同时查询两个type(表)中的内容

GET _mget
{"docs":[{"_index":"testdb","_type":"job1","_id":1},{"_index":"testdb","_type":"job2","_id":2}]
}


可以简写如下

GET testdb/_mget
{"docs":[{"_type":"job1","_id":1},{"_type":"job2","_id":2}]
}

查询job1下的两个文档(两行)

GET testdb/job1/_mget
{"docs":[{"_id":1},{"_id":2}]
}

或者简写成

GET testdb/job1/_mget
{"ids":[1,2]
}

elasticsearch的bulk批量操作

可以合并多个操作,比如index,delete,update,create等等,包括从一个索引到另一个索引:

action_and_meta_data\n
option_source\n
action_and_meta_data\n
option_source\n
….
注意,每两行是一条数据(index,update,create)(delete除外)

看下面的例子,利用bulk同时增加两条数据

POST _bulk
{"index":{"_index":"lagou","_type":"job1","_id":"1"}}
{"title":"python分布式爬虫开发","salary_min":15000,"city":"北京","company":{"name":"百度","company_addr":"北京市软件园"},"public_date":"2019-4-16","comments":15}
{"index":{"_index":"lagou","_type":"job2","_id":"2"}}
{"title":"python django","salary_min":15000,"city":"成都","company":{"name":"百度","company_addr":"成都市软件园"},"public_date":"2019-4-1","comments":50}

映射

创建索引的时候,可以预先定义字段的类型以及相关属性

  • 类比数据库中,我们定义一个表,然后要给每一列定义数据类型(整型,字符型),对于ES来说也是一样,放数据时,对每一个字段指定一种类型.
  • 列类型一旦通过映射创建就不可修改(和关系数据库的不同)

相关属性的配置
类型

类型 解释
String类型 分为两种text、keyword,
text会对内部的内容进行分析,索引,进行倒排索引等
keyword则会当成字符串,不会被分析,只能完全匹配才能找到String(在es5已经被废弃了)
日期类型 date 以及datetime等
数字类型 integer long double等等
bool类型 boolean
binary类型 binary
复杂类型 object、nested(数组形式)
geo类型 geo-point地理位置
专业类型 ip competition
object json里面内置的还有下层{}的对象

下图红框中就是一个nested类型

属性

具体的使用可以看下下面红框内

Elasticsearch查询

elasticserach查询大概分为三类:

  • 基本查询
  • 组合查询
  • 过滤:查询同时,通过filter条件在不影响打分的情况下筛选数据

match查询(使用较多)

后面为关键词,关于python的都会提取出来,match查询会对内容进行分词,并且会自动对传入的关键词进行大小写转换,内置ik分词器会进行切分,如python网站,只要搜到存在的任何一部分,都会返回

GET lagou/job/_search
{"query":{"match":{"title":"python"}}
}

term查询

区别,对传入的值不会做任何处理,就像keyword(见上面的映射.类型),只能查包含整个传入的内容的,一部分也不行,只能完全匹配(例如下面python爬虫,只能找到完全一样的关键词)

GET lagou/job/_search
{"query":{"term":{"title":"python爬虫"}}
}

terms查询

title里传入多个值,只要有一个匹配,就会返回结果

GET lagou/job/_search
{"query":{"term":{"title":["工程师","Django"]}}
}

from控制查询的返回数量

通过这里就可以完成分页处理,从第一条开始查询两条,from从0开始

GET lagou/_serach
{"query":{"match":{"title":"python"}},"from":1,"size":2
}

match_all 返回所有

GET lagou/_search
{
“query”:{
“match_all”:{}
}
}

match_phrase查询:短语查询

“python系统”,将其分词,分为词条,满足词条里面的所有词才会返回结果,slop参数说明两个词条之间的最小距离,比如python和系统之间的距离

GET lagou/_search
{"query":{"match_phrase":{"title":{"query":"python系统","slop":6}}}
}

sort将结果排序

先查询全部,然后对评论数按照降序排序

GET lagou/_search
{"query";{"match_all":{}},"sort":[{"comments":{"order":"desc"}}]
}

range范围查询

range是在query里面的,boost是权重,gte lte是大于等于,小于等于的意思,(带e是等于)
对时间的范围查询,则是以字符串的形式传入

GET lagou / _search {“query”; {“range”: {“comments”: {“gte”: 10,“lte”: 20,“boost”: 2.0}}}
}

★range范围查询原理

https://zhuanlan.zhihu.com/p/164538758

用的最多的是match,range!!!

bool组合查询

bool查询包括了must、should、must_not filter来完成
格式如下:

bool:{"filter":[],"must":[],"should":[],"must_not":[],
}
关键字 作用
filter 用于过滤字段,不参与打分
must 数组里的所有查询必须全部满足
should 与must相反,满足一个或多个都可以

首先我们先插入数据

简单的filter查询

select * from testjob where salary=20


term改为match也可以

select * from testjob where title="Python"

查询时用小写python
查看分析器解析的结果


select * from testjob where (salary=20 OR title=“python”) AND (salary!=30)
select * from testjob where title=“python” or (title=“django” AND salary=30)
过滤空、非空

Scrapy整合项目

将scrapy爬到的item保存到es

新建一个models文件夹,新建es-jobbole.py文件,内容如下
这个文件作用是创建了索引,类似于我们新建了一个数据库,但是还没有往里面放值.

# _*_ coding: utf-8 _*_from datetime import datetime
from elasticsearch_dsl import DocType, Date, Nested, Boolean, \analyzer, Completion, Keyword, Text, Integerfrom elasticsearch_dsl.analysis import CustomAnalyzer as _CustomAnalyzerfrom elasticsearch_dsl.connections import connections# 与服务器进行连接,hosts允许多个,但我们现在连接本地
connections.create_connection(hosts=["localhost"])# class CustomAnalyzer(_CustomAnalyzer):
#     def get_analysis_definition(self):
#         return {}
# ik_analyzer = CustomAnalyzer("ik_max_word", filter=["lowercase"])class ArticleType(DocType):# 伯乐在线文章类型# suggest = Completion(analyzer=ik_analyzer)title = Text(analyzer="ik_max_word") #需要对title进行分词create_date = Date()url = Keyword()url_object_id = Keyword()front_image_url = Keyword()front_image_path = Keyword()praise_nums = Integer()comment_nums = Integer()fav_nums = Integer()tags = Text(analyzer="ik_max_word")content = Text(analyzer="ik_max_word")class Meta:index = "jobbole"  #相当于数据库名doc_type = "article"  #表名if __name__ == "__main__":ArticleType.init() #根据我们定义的类,直接生成mapping#这样执行之后,那么是定义的哪一个index,哪个type之下呢,所以我们需要Meta

单独执行这个文件后,我们可以在es界面看到创建的jobbole索引

现在我们写pipelines.py使爬到的数据真正保存到es

class ElasticsearchPipeline(object):#将数据写入esdef process_item(self,item,spider):#将item转换为es的数据,需要elastcsearch-dsl(python接口包)article = ArticleType()article.title = item['title']article.create_date = item['create_date']article.content = remove_tags(item['content'])article.front_image_url = item['front_image_url']if "front_image_path" in item:article.front_image_path = item['front_image_path']article.praise_nums = item["praise_nums"]article.fav_nums = item['fav_nums']article.comment_nums = item['comment_nums']article.url = item['url']article.tags = item['tags']article.meta.id = item['url_object_id']# article.suggest = [{"input":[],"weight":2}]#10,7代表的是权重article.suggest = gen_suggest(ArticleType._doc_type.index,((article.title,10),(article.tags,7)))article.save()return item

然后在settings.py中更改pipeline的执行顺序

ITEM_PIPELINES = {# 'ArticleSpider.pipelines.JsonWithEncodingPipeline': 2,# 'scrapy.pipelines.images.ImagesPipeline':1,#  'ArticleSpider.pipelines.ArticleImagePipeline':1#'ArticleSpider.pipelines.MysqlPipeline':1#  'ArticleSpider.pipelines.MysqlTwistedPipeline':1'ArticleSpider.pipelines.ElasticsearchPipeline':1
}

执行main.py文件后,去 http://127.0.0.1:9100/ 查看

Django搭建搜索界面


文件目录如下

前端界面文件放在/templates文件夹 , css、js文件放在/static文件夹,为了使前端界面能够找到cssjs , 我们在settings.py中添加

STATIC_URL = '/static/'STATICFILES_DIRS = [os.path.join(BASE_DIR, "static")
]

然后在urls.py中添加

from django.conf.urls import url
from django.contrib import admin
from django.views.generic import TemplateViewurlpatterns = [url(r'^admin/', admin.site.urls),#url(r'^index', index,name = 'index'),url(r'^$',TemplateView.as_view(template_name="index.html"),name="index")]

进入项目所在目录,找到manage.py目录打开cmd,输入下面命令启动Django

python manage.py runserver

浏览器打开 http://127.0.0.1:8000/ ,可以看到如下界面

为了实现搜索建议功能,首先来看一下编辑距离
编辑距离是一种字符之间相似程度的计算方法:linux、linx,即两个字符串之间的编辑距离等于使一个字符串变成另外一个字符串而进行的(1)插入、(2)删除、(3)替换或(4)相邻字符交换位置而进行操作的最少次数.
比如: ed("recognize","recoginze") == 1, 需要交换两个相邻in .

编辑距离会在fuzzy搜索 中使用到,下面是一个简单的fuzzy搜索案例:
fuzziness就是编辑距离
prefix_length是前缀长度

GET /_search
{"query": {"fuzzy": {"title": {"value": "linux","fuzziness": 0.5,"prefix_length": 0}}},"_source": ["title"]
}

ES的suggest

POST /jobbole/_search?pretty
{"suggest": {"my_suggest" : {"text" : "linux","completion" : {"field" : "suggest","fuzzy":{"fuzziness":2}}}},"_source": "title"
}

实现搜索建议

什么是搜索建议,就是如下图所示那样,当 我们在搜索框内输入某个关键词时,会自动给出联想提示

官方API
https://www.elastic.co/guide/en/elasticsearch/reference/current/search-suggesters-completion.html
首先在es_jobbole.py中重写suggest,完成后代码如下:

# _*_ coding: utf-8 _*_from datetime import datetime
from elasticsearch_dsl import DocType, Date, Nested, Boolean, \analyzer, Completion, Keyword, Text, Integerfrom elasticsearch_dsl.analysis import CustomAnalyzer as _CustomAnalyzerfrom elasticsearch_dsl.connections import connections
# 与服务器进行连接,hosts允许多个,但我们现在连接本地
connections.create_connection(hosts=["localhost"])#搜索建议,需要从elasticsearch_dsl.analysis导入CustomAnalyzer
class CustomAnalyzer(_CustomAnalyzer):def get_analysis_definition(self):return {}
ik_analyzer = CustomAnalyzer("ik_max_word", filter=["lowercase"])class ArticleType(DocType):# 伯乐在线文章类型suggest = Completion(analyzer=ik_analyzer) #这个会有问题,所以我们自己重写title = Text(analyzer="ik_max_word") #需要对title进行分词create_date = Date()url = Keyword()url_object_id = Keyword()front_image_url = Keyword()front_image_path = Keyword()praise_nums = Integer()comment_nums = Integer()fav_nums = Integer()tags = Text(analyzer="ik_max_word")content = Text(analyzer="ik_max_word")class Meta:index = "jobbole"  #相当于数据库名doc_type = "article"  #表名if __name__ == "__main__":ArticleType.init() #根据我们定义的类,直接生成mapping#这样执行之后,那么是定义的哪一个index,哪个type之下呢,所以我们需要Meta

添加的代码如下

from elasticsearch_dsl.analysis import CustomAnalyzer as _CustomAnalyzer#搜索建议,需要从elasticsearch_dsl.analysis导入CustomAnalyzer
class CustomAnalyzer(_CustomAnalyzer):def get_analysis_definition(self):return {}
ik_analyzer = CustomAnalyzer("ik_max_word", filter=["lowercase"])
......
......
......
suggest = Completion(analyzer=ik_analyzer)

报错1

TypeError: analyze() got an unexpected keyword argument 'analyzer'

解决1
参考: https://blog.csdn.net/javakklam/article/details/80114837

words = es.indices.analyze(index=index,body={'text':text,'analyzer':"ik_max_word"},params={'filter':["lowercase"]})

报错2

analyzed_words = set([r['token'] for r in words if len(r['token'])>1])
TypeError: string indices must be integers

解决2

analyzed_words = set([r["token"] for r in words["tokens"] if len(r["token"]) > 1])

生成搜索建议词
这部分我们在pipelines.py

def gen_suggest(index,info_tuple):used_words = set()suggests = []for text,weight in info_tuple:if text:words = es.indices.analyze(index=index,body={'text':text,'analyzer':"ik_max_word"},params={'filter':["lowercase"]})#analyzed_words = set([r['token'] for r in words if len(r['token'])>1])analyzed_words = set([r["token"] for r in words["tokens"] if len(r["token"]) > 1])new_words = analyzed_words - used_words #集合相减,把已经存在的词过滤掉else:new_words = set()if new_words:suggests.append({"input":list(new_words),"weight":weight})return suggestsclass ElasticsearchPipeline(object):#将数据写入esdef process_item(self,item,spider):#将item转换为es的数据,需要elastcsearch-dsl(python接口包)article = ArticleType()article.title = item['title']article.create_date = item['create_date']article.content = remove_tags(item['content'])article.front_image_url = item['front_image_url']if "front_image_path" in item:article.front_image_path = item['front_image_path']article.praise_nums = item["praise_nums"]article.fav_nums = item['fav_nums']article.comment_nums = item['comment_nums']article.url = item['url']article.tags = item['tags']article.meta.id = item['url_object_id']# article.suggest = [{"input":[],"weight":2}]#10,7代表的是权重article.suggest = gen_suggest(ArticleType._doc_type.index,((article.title,10),(article.tags,7)))article.save()return item

处理上面的错误后,我们运行main.py,爬到一些数据后停止运行,去es界面查看生成的suggest

报错1
对于Es搜索自动提示功能debug出现Search object has no attribute execute_suggest.的解决方法

这一问题的出现主要是elasticsearch-dsl的改版,导致以前的方法被新版的方法替代或者不再使用。
旧版本代码:

class SearchSuggest(View):def get(self, request):key_words = request.GET.get('s', '')re_datas = []if key_words:s = ArticleType.search()s = s.suggest('my_suggest', key_words, completion={"field": "suggest", "fuzzy": {"fuzziness": 2},"size": 10}suggestions = s.execute_suggest()for match in suggestions.my_suggest[0].options:source = match._sourcere_datas.append(source["title"])return HttpResponse(json.dumps(re_datas), content_type="application/json")

新版本代码:
新版本之后execute_suggest()方法就不再使用,取而代之的是execute()方法

 class SearchSuggest(View):def get(self, request):key_words = request.GET.get('s', '')re_datas = []if key_words:s = ArticleType.search()s = s.suggest('my_suggest', key_words, completion={"field": "suggest", "fuzzy": {"fuzziness": 2},"size": 10})suggestions = s.execute()  suggestion = suggestions.suggestfor match in suggestion.my_suggest[0].options:source = match._sourcere_datas.append(source["title"])return HttpResponse(json.dumps(re_datas), content_type="application/json")


报错2

AttributeError: 'Response' object has no attribute 'index'

原因是解析json返回的数据时出错,应改为
for match in suggestions.suggest.my_suggest[0].options[:10]:

搜索展示界面

报错

HTTPConnectionPool(host='localhost', port=9200): Read timed out. (read timeout=10))

原因是elasticsearch挂了,重启一下就好了


2019-5-15 后续常用功能

在原有基础上增加字段(mapping映射)

PUT jingdong/comment/_mapping
{"properties": {"wordcloud_negative": {"type": "string"},"proportion_positive": {"type": "double"},"proportion_negative": {"type": "double"}}
}

更新某个字段内容或者用GET全部更新

POST jingdong/comment/2/_update
{"doc":{"comments":20}
}

SpringBoot 整合 ES

官方文档
https://www.elastic.co/guide/en/elasticsearch/client/java-rest/current/java-rest-high.html

准备工作

功能测试(坑)

同步mysql数据到ElasticSearch

Elasticsearch就是专门用于搜索的,所以我们会将新增的数据放入Elasticsearch中用于搜索,就有这样的常见的场景,需要将Mysql中的数据同步到Elasticsearch中。
Mysql数据同步到ES中分为两种,分别是全量同步和增量同步。

  • 全量同步是指全部将数据同步到es,通常是刚建立es,第一次同步时使用。
  • 增量同步是指将后续的更新、插入记录同步到es。(删除记录没有办法同步,只能两边执行自己的删除命令)

Mysql与ES的数据同步实现方式, 业界有一些开源方案,开源中间件来实现:

  1. 基于Mysql的binlog日志订阅:binlog日志是Mysql用来记录数据实时的变化。 这里主要的是binlog同步组件,目前实现的有国内的阿里巴巴开发的canal。

  2. ES官方数据收集和同步组件logstash

Elasticsearch学习记录相关推荐

  1. ElasticSearch学习笔记-ngram、中文拼音、简繁体搜索记录

    ElasticSearch版本:elasticsearch-7.3.0 ElasticSearch相关插件安装可以参考: ElasticSearch学习笔记-插件安装记录_人生偌只如初见的博客-CSD ...

  2. ElasticSearch学习笔记记录5【图灵Fox】

    上述代码可以展示动态映射的概念. 学习视频: [2022最新版]ElasticSearch学习教程合集,从ElasticSearch入门到实战几乎包含你需要的所有操作_哔哩哔哩_bilibili

  3. ElasticSearch学习笔记记录4【图灵Fox】

      上述当value为iPhone时是匹配不到数据的,根据analyze分词器查看效果显示,value应该为小写的字母才可以. 学习视频: [2022最新版]ElasticSearch学习教程合集,从 ...

  4. ElasticSearch学习总结(三):查询总结

    ElasticSearch学习总结(三):查询总结 本文主要对Elasticsearch中查询相关的知识做一个简单的总结,内容主要包括查询的评分机制,查询改写,过滤器,以及对常见的查询做一个简单的分类 ...

  5. Elasticseach 从零开始学习记录(四) - 整合springboot2.x

    1. 我的springboot版本为2.2.6.RELEASE, 本文推荐elasticsearch-rest-high-level-client在           springboot里集成el ...

  6. Elasticseach 从零开始学习记录(三) - 分布式部署

    1. 先关闭elasticseach,登录root账户,修改之前解压的es文件夹名为master,好区分,并重新给改名后的文件夹赋esuser权限. mv elasticsearch-7.14.1 e ...

  7. Elasticseach 从零开始学习记录(二) - Head插件

    安装Head插件的原因: 可以提供友好的web界面,还可以实现基本信息的查看,rest请求的模拟,以及数据的基本检索. 1. 检查服务器是否已经安装node.js 如未安装,自行百度安装node 2. ...

  8. Elasticseach 从零开始学习记录(一) - 单实例环境搭建

    声明: 本文章是本人第一次学习ES,把过程和过程中遇到问题,以及百度后解决方案记录下来,如有问题,希望高手指出,谢谢. 环境:服务器为linux centos7 64位, jdk8 , ES7.14. ...

  9. Elasticsearch 学习(二).实战使用

    Elasticsearch 学习(二).实战使用 参考:http://www.passjava.cn/#/01.PassJava/02.PassJava_Architecture/15.Elastic ...

最新文章

  1. 在SQL Server 20005中修改存储过程
  2. 从单体到混乱的微服务,阿里云托管式服务网格是如何诞生的?
  3. redis 备份导出rdb_redis简单安装学习
  4. poj-1284(Primitive Roots)(欧拉函数运用)
  5. Windows窗口分析
  6. 单点登录之实战CAS5.1.x(六)——REST协议
  7. golang 线程 Java线程_Golang 学习笔记(06)—— 多线程
  8. 1023 组个最小数 (20 分)(c语言)
  9. ETL学习之四:SQL Server Integration Services入门
  10. 【PAT - 甲级1012】The Best Rank (25分)
  11. 阿里技术专家:进击的 Java ,云原生时代的蜕变
  12. 易语言识别语音的方法
  13. VC6中编译器/zm问题
  14. B端产品运营基本工作内容
  15. kd718和kb688参数_GJK SPP 5BGK AEC F04A tB9 D4 RMP
  16. html 强制用ie浏览,强制指定IE浏览器版本
  17. 三星Galaxy十周年,它给了你一款能买到的折叠手机
  18. 自己制作icon图标
  19. 简单美化 Win 10 的 CMD 命令行终端界面
  20. 物联网实战之基于OneNET的智能农业系统

热门文章

  1. Spring学习12之整合Mybatis
  2. jdk中的动态代理和cglib中动态代理的区别
  3. C~K的班级_JAVA
  4. Period_JAVA
  5. 顺序表应用4:元素位置互换之逆置算法
  6. 了解CMS(Concurrent Mark-Sweep)垃圾回收器
  7. 《卓有成效的程序员》----读书笔记二
  8. java学习笔记14--多线程编程基础1
  9. 世界围棋人机大战、顶峰对决第一盘:围棋世界冠军Lee Sedol(李世石,围棋职业九段)对战Google DeepMind AlphaGo围棋程序,Google AlphaGo首战告捷
  10. 程序员面试题精选100题(22)-整数二进制表示中1的个数[算法]