本文以 Elasticsearch 6.2.4为例。

经过前面的基础入门,我们对ES的基本操作也会了。现在来学习ES最强大的部分:全文检索。

准备工作

批量导入数据

先需要准备点数据,然后导入:

wget https://raw.githubusercontent.com/elastic/elasticsearch/master/docs/src/test/resources/accounts.json

curl -H "Content-Type: application/json" -XPOST "localhost:9200/bank/account/_bulk" --data-binary "@accounts.json"

这样我们就导入了1000条数据到ES。

注意:accounts.json每行必须以\n换行。如果提示The bulk request must be terminated by a newline [\n],请检查最后一行是否以\n换行。

index是bank。我们可以查看现在有哪些index:

curl "localhost:9200/_cat/indices?format=json&pretty"

结果:

[
{
"health" : "yellow",
"status" : "open",
"index" : "bank",
"uuid" : "MDxR02uESgKSynX6k8B-og",
"pri" : "5",
"rep" : "1",
"docs.count" : "1000",
"docs.deleted" : "0",
"store.size" : "474.6kb",
"pri.store.size" : "474.6kb"
}
]

使用kibana可视化数据

该小节是可选的,如果不感兴趣,可以跳过。

该小节要求你已经搭建好了ElasticSearch + Kibana。

打开kibana web地址:http://127.0.0.1:5601,依次打开:Management

-> Kibana -> Index Patterns ,选择Create Index Pattern

a. Index pattern 输入:bank

b. 点击Create。

然后打开Discover,选择 bank 就能看到刚才导入的数据了。

我们在可视化界面里检索数据:

是不是很酷!

接下来我们使用API来实现检索。

查询

URI检索

uri检索是通过提供请求参数纯粹使用URI来执行搜索请求。

GET /bank/_search?q=Virginia&pretty
GET /bank/_search?q=firstname:Virginia

curl:

curl -XGET "localhost:9200/bank/_search?q=Virginia&pretty"
curl -XGET "localhost:9200/bank/_search?q=firstname:Virginia&pretty"

解释:检索关键字为"Virginia"的结果。结果示例:

{
"took": 4,
"timed_out": false,
"_shards": {
"total": 5,
"successful": 5,
"skipped": 0,
"failed": 0
},
"hits": {
"total": 2,
"max_score": 4.631368,
"hits": [
{
"_index": "bank",
"_type": "account",
"_id": "298",
"_score": 4.631368,
"_source": {
"account_number": 298,
"balance": 34334,
"firstname": "Bullock",
"lastname": "Marsh",
"age": 20,
"gender": "M",
"address": "589 Virginia Place",
"employer": "Renovize",
"email": "bullockmarsh@renovize.com",
"city": "Coinjock",
"state": "UT"
}
},
{
"_index": "bank",
"_type": "account",
"_id": "25",
"_score": 4.6146765,
"_source": {
"account_number": 25,
"balance": 40540,
"firstname": "Virginia",
"lastname": "Ayala",
"age": 39,
"gender": "F",
"address": "171 Putnam Avenue",
"employer": "Filodyne",
"email": "virginiaayala@filodyne.com",
"city": "Nicholson",
"state": "PA"
}
}
]
}
}

返回字段含义:

  • took – Elasticsearch执行搜索的时间(以毫秒为单位)
  • timed_out – 搜索是否超时
  • _shards – 搜索了多少个分片,以及搜索成功/失败分片的计数
  • hits – 搜索结果,是个对象
  • hits.total – 符合我们搜索条件的文档总数
  • hits.hits – 实际的搜索结果数组(默认为前10个文档)
  • hits.sort - 对结果进行排序(如果按score排序则没有该字段)
  • hits._score、max_score - 暂时忽略这些字段

参数:

  • q 查询字符串(映射到query_string查询)
  • df 在查询中未定义字段前缀时使用的默认字段。
  • analyzer 分析查询字符串时要使用的分析器名称。
  • sort 排序。可以是fieldNamefieldName:asc/ 的形式fieldName:descfieldName可以是文档中的实际字段,也可以是特殊_score名称,表示基于分数的排序。可以有几个sort参数(顺序很重要)。
  • timeout 搜索超时。默认为无超时。
  • from 从命中的索引开始返回。默认为0。
  • size 要返回的点击次数。默认为10。
  • default_operator 要使用的默认运算符可以是AND或 OR。默认为OR。

详见: https://www.elastic.co/guide/en/elasticsearch/reference/6.2/search-uri-request.html

示例:

GET /bank/_search?q=*&sort=account_number:asc&pretty

解释:所有结果通过account_number字段升序排列。默认只返回前10条。

下面的查询与上面的含义一致:

GET /bank/_search
{
"query": {
"multi_match" : {
"query" : "Virginia",
"fields" : ["_all"]
}
}
} GET /bank/_search
{
"query": { "match_all": {} },
"sort": [
{ "account_number": "asc" }
]
}

通常我们会采用传JSON方式查询。Elasticsearch提供了一种JSON样式的特定于域的语言,可用于执行查询。这被称为查询DSL。

注意:上述的查询里面我们仅指定了index,并没有指定type,那么ES将不会区分type。如果想区分,请在URI后面追加type。示例:GET /bank/account/_search

match查询

GET /bank/_search
{
"query" : {
"match" : { "address" : "Avenue" }
}
}

curl:

curl -XGET -H "Content-Type: application/json" "localhost:9200/bank/_search?pretty" -d '{"query":{"match":{"address":"Avenue"}}}'

上述查询返回结果是address含有Avenue的结果。

term查询

GET /bank/_search
{
"query" : {
"term" : { "address" : "Avenue" }
}
}

curl:

curl -XGET -H "Content-Type: application/json" "localhost:9200/bank/_search?pretty" -d '{"query":{"term":{"address":"Avenue"}}}'

上述查询返回结果是address等于Avenue的结果。

注:如果一个字段既需要分词搜索,又需要精准匹配,最好是一开始设置mapping的时候就设置正确。例如:通过增加.keyword字段来支持精准匹配:

{
"type": "text",
"fields": {
"keyword": {
"type": "keyword",
"ignore_above": 256
}
}
}

这样相当于有addressaddress.keyword两个字段。这个后面mapping章节再讲解。

分页(from/size)

分页使用关键字from、size,分别表示偏移量、分页大小。

GET /bank/_search
{
"query": { "match_all": {} },
"from": 0,
"size": 2
}

from默认是0,size默认是10。

注意:ES的from、size分页不是真正的分页,称之为浅分页。from+ size不能超过index.max_result_window 默认为10,000 的索引设置。有关 更有效的深度滚动方法,请参阅 ScrollSearch After API

排序(sort)

字段排序关键字是sort。支持升序(asc)、降序(desc)。默认是对_score字段进行排序。

GET /bank/_search
{
"query": { "match_all": {} },
"sort": [
{ "account_number": "asc" }
],
"from":0,
"size":10
}

多个字段排序:

GET /bank/_search
{
"query": { "match_all": {} },
"sort": [
{ "account_number": "asc" },
{ "_score": "asc" }
],
"from":0,
"size":10
}

先按照account_number排序,再按照_score排序。

按脚本排序

允许基于自定义脚本进行排序,这是一个示例:

GET bank/account/_search
{
"query": { "range": { "age": {"gt": 20} }},
"sort" : {
"_script" : {
"type" : "number",
"script" : {
"lang": "painless",
"source": "doc['account_number'].value * params.factor",
"params" : {
"factor" : 1.1
}
},
"order" : "asc"
}
}
}

上述查询是使用脚本进行排序:按 account_number*1.1 的结果进行升序。其中lang指的是使用的脚本语言类型为painlesspainless支持Math.log函数。

上述例子仅仅是演示使用方法,没有实际含义。

过滤字段

默认情况下,ES返回所有字段。这被称为源(_source搜索命中中的字段)。如果我们不希望返回所有字段,我们可以只请求返回源中的几个字段。

GET /bank/_search
{
"query": { "match_all": {} },
"_source": ["account_number", "balance"]
}

通过_source关键字可以实现字段过滤。

返回脚本字段

可以通过脚本动态返回新定义字段。示例:

GET bank/account/_search
{
"query" : {
"match_all": {}
},
"size":2,
"script_fields" : {
"age2" : {
"script" : {
"lang": "painless",
"source": "doc['age'].value * 2"
}
},
"age3" : {
"script" : {
"lang": "painless",
"source": "params['_source']['age'] * params.factor",
"params" : {
"factor" : 2.0
}
}
}
}
}

结果:

{
"took": 2,
"timed_out": false,
"_shards": {
"total": 5,
"successful": 5,
"skipped": 0,
"failed": 0
},
"hits": {
"total": 1000,
"max_score": 1,
"hits": [
{
"_index": "bank",
"_type": "account",
"_id": "25",
"_score": 1,
"fields": {
"age3": [
78
],
"age2": [
78
]
}
},
{
"_index": "bank",
"_type": "account",
"_id": "44",
"_score": 1,
"fields": {
"age3": [
74
],
"age2": [
74
]
}
}
]
}
}

注意:使用doc['my_field_name'].value比使用params['_source']['my_field_name']更快更效率,推荐使用。

AND查询

如果我们想同时查询符合A和B字段的结果,该怎么查呢?可以使用must关键字组合。

GET /bank/_search
{
"query": {
"bool": {
"must": [
{ "match": { "address": "mill" } },
{ "match": { "address": "lane" } }
]
}
}
} GET /bank/_search
{
"query": {
"bool": {
"must": [
{ "match": { "account_number":136 } },
{ "match": { "address": "lane" } },
{ "match": { "city": "Urie" } }
]
}
}
}

must也等价于:

GET /bank/_search
{
"query": {
"bool": {
"must": [
{ "match": { "address": "mill" } }
],
"must": [
{ "match": { "address": "lane" } }
]
}
}
}

这种相当于先查询A再查询B,而上面的则是同时查询符合A和B,但结果是一样的,执行效率可能有差异。有知道原因的朋友可以告知。

OR查询

ES使用should关键字来实现OR查询。

GET /bank/_search
{
"query": {
"bool": {
"should": [
{ "match": { "account_number":136 } },
{ "match": { "address": "lane" } },
{ "match": { "city": "Urie" } }
]
}
}
}

AND取反查

must_not关键字实现了既不包含A也不包含B的查询。

GET /bank/_search
{
"query": {
"bool": {
"must_not": [
{ "match": { "address": "mill" } },
{ "match": { "address": "lane" } }
]
}
}
}

表示 address 字段需要符合既不包含 mill 也不包含 lane。

布尔组合查询

我们可以组合 must 、should 、must_not、filter 进行复杂的查询。

  • A AND NOT B
GET /bank/_search
{
"query": {
"bool": {
"must": [
{ "match": { "age": 40 } }
],
"must_not": [
{ "match": { "state": "ID" } }
]
}
}
}

相当于SQL:

select * from bank where age=40 and state!= "ID";
  • A AND (B OR C)
GET /bank/_search
{
"query":{
"bool":{
"must":[
{"match":{"age":39}},
{"bool":{"should":[
{"match":{"city":"Nicholson"}},
{"match":{"city":"Yardville"}}
]}
}
]
}
}
}

相当于SQL:

select * from bank where age=39 and (city="Nicholson" or city="Yardville");

范围查询

GET /bank/_search
{
"query": {
"bool": {
"must": { "match_all": {} },
"filter": {
"range": {
"balance": {
"gte": 20000,
"lte": 30000
}
}
}
}
}
}
  • A AND (B OR C) AND (D BETWEEN E, F)
GET /bank/_search
{
"query":{
"bool":{
"must":[
{"match":{"age":39}},
{"bool":{"should":[
{"match":{"city":"Nicholson"}},
{"match":{"city":"Yardville"}}
]}
},
{"bool":{"filter": {"range": {
"balance": {
"gte": 20000,
"lte": 30000
}}}
}
}
]
}
}
}

相当于SQL:

select * from bank where age=39 and (city="Nicholson" or city="Yardville") and (balance between 20000 and 30000);

如果仅仅是单字段范围查询,也可以直接省略 must、filter等关键字:

GET /bank/_search
{
"query":{
"range":{
"balance":{
"gte":20000,
"lte":30000
}
}
}
}

相当于SQL:

select * from bank where balance between 20000 and 30000;

多字段范围查询:

GET /bank/_search
{
"query": {
"bool": {
"must": { "match_all": {} },
"filter": {
"bool":{
"must":[
{"range": {"balance": {"gte": 20000,"lte": 30000}}},
{"range": {"age": {"gte": 30}}}
]
}
}
}
}
}

查询字段不存在或者为0的值

GET /bank/doc/_search
{
"query":{
"bool":{
"should":[
{
"term":{"age":0}
},
{
"bool":{
"must_not":[{"exists":{"field":"age"}}]
}
}
]
}
}
}

高亮结果

ES可以高亮返回结果里的关键字,使用html标记标出。

GET bank/account/_search
{
"query" : {
"match": { "address": "Avenue" }
},
"from": 0,
"size": 1,
"highlight" : {
"require_field_match": false,
"fields": {
"*" : { }
}
}
}

输出:

{
"took": 10,
"timed_out": false,
"_shards": {
"total": 5,
"successful": 5,
"skipped": 0,
"failed": 0
},
"hits": {
"total": 214,
"max_score": 1.5814995,
"hits": [
{
"_index": "bank",
"_type": "account",
"_id": "102",
"_score": 1.5814995,
"_source": {
"account_number": 102,
"balance": 29712,
"firstname": "Dena",
"lastname": "Olson",
"age": 27,
"gender": "F",
"address": "759 Newkirk Avenue",
"employer": "Hinway",
"email": "denaolson@hinway.com",
"city": "Choctaw",
"state": "NJ"
},
"highlight": {
"address": [
"759 Newkirk <em>Avenue</em>"
]
}
}
]
}
}

返回结果里的highlight部分就是高亮结果,默认使用<em>标出。如果需要修改,可以使用pre_tags设置修改:

"fields": {
"*" : { "pre_tags" : ["<strong>"], "post_tags" : ["</strong>"] }
}

*代表所有字段都高亮,也可以只高亮具体的字段,直接用具体字段替换*即可。

require_field_match:默认情况下,仅突出显示包含查询匹配的字段。设置require_field_match为false突出显示所有字段。默认为true。详见:https://www.elastic.co/guide/en/elasticsearch/reference/6.2/search-request-highlighting.html

聚合查询

GET /bank/_search
{
"size": 0,
"aggs": {
"group_by_state": {
"terms": {
"field": "state.keyword"
}
}
}
}

结果:

{
"took": 29,
"timed_out": false,
"_shards": {
"total": 5,
"successful": 5,
"skipped" : 0,
"failed": 0
},
"hits" : {
"total" : 1000,
"max_score" : 0.0,
"hits" : [ ]
},
"aggregations" : {
"group_by_state" : {
"doc_count_error_upper_bound": 20,
"sum_other_doc_count": 770,
"buckets" : [ {
"key" : "ID",
"doc_count" : 27
}, {
"key" : "TX",
"doc_count" : 27
}, {
"key" : "AL",
"doc_count" : 25
}, {
"key" : "MD",
"doc_count" : 25
}, {
"key" : "TN",
"doc_count" : 23
}, {
"key" : "MA",
"doc_count" : 21
}, {
"key" : "NC",
"doc_count" : 21
}, {
"key" : "ND",
"doc_count" : 21
}, {
"key" : "ME",
"doc_count" : 20
}, {
"key" : "MO",
"doc_count" : 20
} ]
}
}
}

查询结果返回了ID州(Idaho)有27个账户,TX州(Texas)有27个账户。

相当于SQL:

SELECT state, COUNT(*) FROM bank GROUP BY state ORDER BY COUNT(*) DESC

该查询意思是按照字段state分组,返回前10个聚合结果。

其中size设置为0意思是不返回文档内容,仅返回聚合结果。state.keyword表示字段精确匹配,因为使用模糊匹配性能很低,所以不支持。

如果需要聚合的时候对某个字段去重,使用cardinality关键字即可:

GET /bank/_search
{
"size": 0,
"aggs": {
"group_by_state": {
"cardinality": {
"field": "state.keyword"
}
}
}
}

多重聚合

我们可以在聚合的基础上再进行聚合,例如求和、求平均值等等。

GET /bank/_search
{
"size": 0,
"aggs": {
"group_by_state": {
"terms": {
"field": "state.keyword"
},
"aggs": {
"average_balance": {
"avg": {
"field": "balance"
}
}
}
}
}
}

上述查询实现了在前一个聚合的基础上,按州计算平均帐户余额(同样仅针对按降序排序的前10个州)。

我们可以在聚合中任意嵌套聚合,以从数据中提取所需的统计数据。

在前一个聚合的基础上,我们现在按降序排列平均余额:

GET /bank/_search
{
"size": 0,
"aggs": {
"group_by_state": {
"terms": {
"field": "state.keyword",
"order": {
"average_balance": "desc"
}
},
"aggs": {
"average_balance": {
"avg": {
"field": "balance"
}
}
}
}
}
}

这里基于第二个聚合结果进行倒序排列。其实上一个例子隐藏了默认排序,也就是默认按照_sort(分值)倒序:

GET /bank/_search
{
"size": 0,
"aggs": {
"group_by_state": {
"terms": {
"field": "state.keyword",
"order": {
"_sort": "desc"
}
},
"aggs": {
"average_balance": {
"avg": {
"field": "balance"
}
}
}
}
}
}

此示例演示了我们如何按年龄段(20-29岁,30-39岁和40-49岁)进行分组,然后按性别分组,最后得到每个年龄段的平均帐户余额:

GET /bank/_search
{
"size": 0,
"aggs": {
"group_by_age": {
"range": {
"field": "age",
"ranges": [
{
"from": 20,
"to": 30
},
{
"from": 30,
"to": 40
},
{
"from": 40,
"to": 50
}
]
},
"aggs": {
"group_by_gender": {
"terms": {
"field": "gender.keyword"
},
"aggs": {
"average_balance": {
"avg": {
"field": "balance"
}
}
}
}
}
}
}
}

这个结果就复杂了,属于嵌套分组,结果也是嵌套的:

{
"took": 5,
"timed_out": false,
"_shards": {
"total": 5,
"successful": 5,
"skipped": 0,
"failed": 0
},
"hits": {
"total": 1000,
"max_score": 0,
"hits": []
},
"aggregations": {
"group_by_age": {
"buckets": [
{
"key": "20.0-30.0",
"from": 20,
"to": 30,
"doc_count": 451,
"group_by_gender": {
"doc_count_error_upper_bound": 0,
"sum_other_doc_count": 0,
"buckets": [
{
"key": "M",
"doc_count": 232,
"average_balance": {
"value": 27374.05172413793
}
},
{
"key": "F",
"doc_count": 219,
"average_balance": {
"value": 25341.260273972603
}
}
]
}
},
{
"key": "30.0-40.0",
"from": 30,
"to": 40,
"doc_count": 504,
"group_by_gender": {
"doc_count_error_upper_bound": 0,
"sum_other_doc_count": 0,
"buckets": [
{
"key": "F",
"doc_count": 253,
"average_balance": {
"value": 25670.869565217392
}
},
{
"key": "M",
"doc_count": 251,
"average_balance": {
"value": 24288.239043824702
}
}
]
}
},
{
"key": "40.0-50.0",
"from": 40,
"to": 50,
"doc_count": 45,
"group_by_gender": {
"doc_count_error_upper_bound": 0,
"sum_other_doc_count": 0,
"buckets": [
{
"key": "M",
"doc_count": 24,
"average_balance": {
"value": 26474.958333333332
}
},
{
"key": "F",
"doc_count": 21,
"average_balance": {
"value": 27992.571428571428
}
}
]
}
}
]
}
}
}

term与match查询

首先大家看下面的例子有什么区别:

已知条件:ES里address171 Putnam Avenue的数据有1条;addressPutnam的数据有0条。index为bank,type为account,文档ID为25。

GET /bank/_search
{
"query": {
"match" : {
"address" : "Putnam"
}
}
} GET /bank/_search
{
"query": {
"match" : {
"address.keyword" : "Putnam"
}
}
} GET /bank/_search
{
"query": {
"term" : {
"address" : "Putnam"
}
}
}

结果:

1、第一个能匹配到数据,因为会分词查询。

2、第二个不能匹配到数据,因为不分词的话没有该条数据。

3、结果不确定。需要看实际是怎么分词的。

我们通过下列查询可以知晓该条数据字段address的分词情况:

GET /bank/account/25/_termvectors?fields=address

结果:

{
"_index": "bank",
"_type": "account",
"_id": "25",
"_version": 1,
"found": true,
"took": 0,
"term_vectors": {
"address": {
"field_statistics": {
"sum_doc_freq": 591,
"doc_count": 197,
"sum_ttf": 591
},
"terms": {
"171": {
"term_freq": 1,
"tokens": [
{
"position": 0,
"start_offset": 0,
"end_offset": 3
}
]
},
"avenue": {
"term_freq": 1,
"tokens": [
{
"position": 2,
"start_offset": 11,
"end_offset": 17
}
]
},
"putnam": {
"term_freq": 1,
"tokens": [
{
"position": 1,
"start_offset": 4,
"end_offset": 10
}
]
}
}
}
}
}

可以看出该条数据字段address一共分了3个词:

171
avenue
putnam

现在可以得出第三个查询的答案:匹配不到!但值改成小写的putnam又能匹配到了!

原因是:

  • term query 查询的是倒排索引中确切的term
  • match query 会对filed进行分词操作,然后再查询

由于Putnam不在分词里(大小写敏感),所以匹配不到。match query先对filed进行分词,也就是分成putnam,再去匹配倒排索引中的term,所以能匹配到。

standard analyzer 分词器分词默认会将大写字母全部转为小写字母。

参考

1、Getting Started | Elasticsearch Reference [6.2] | Elastic

https://www.elastic.co/guide/en/elasticsearch/reference/6.2/getting-started.html

2、Elasticsearch 5.x 关于term query和match query的认识 - wangchuanfu - 博客园

https://www.cnblogs.com/wangchuanfu/p/7444253.html

Elasticsearch实践(二):搜索的更多相关文章

  1. Elasticsearch学习之深入搜索二 --- 搜索底层原理剖析

    1. 普通match如何转换为term+should { "match": { "title": "java elasticsearch"} ...

  2. elasticsearch的rest搜索--- 查询

    目录: 一.针对这次装B 的解释 二.下载,安装插件elasticsearch-1.7.0   三.索引的mapping 四. 查询 五.对于相关度的大牛的文档 四. 查询 1. 查询的官网的文档   ...

  3. ElasticStack系列之十二 & 搜索结果研究

    问题 使用 ElasticSearch 做搜索 时,比如用户输入 --> 柠檬,搜出来的结果 --> 柠檬汽水,柠檬味牙膏等在前面,真正想要的水果那个 柠檬 在后面.已经在中文分词中加了 ...

  4. elasticsearch实现网站搜索

    使用elasticsearch 实现网站搜索,可以支持商品搜索,筛选项过滤搜索 ,价格排序, 打分 筛选项聚合,还有其他综合排序 后续推出搜索人工干预排序,根据销量,好评率,售卖率 进行全方位的搜索实 ...

  5. ElasticSearch(二):文档的基本CRUD与批量操作

    ElasticSearch(二):文档的基本CRUD与批量操作 学习课程链接<Elasticsearch核心技术与实战> Create 文档 支持自动生成文档_id和指定文档_id两种方式 ...

  6. ElasticSearch 连载二 中文分词

    ElasticSearch 连载二 中文分词 上一章ElasticSearch 连载一 基础入门 对Elastic的概念.安装以及基础操作进行了介绍. 那是不是有童鞋会有以下几个问题呢? 什么是中文分 ...

  7. Elasticsearch入门教程(六):Elasticsearch查询(二)

    原文:Elasticsearch入门教程(六):Elasticsearch查询(二) 版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明. 本文链接:h ...

  8. 畅购商城(五):Elasticsearch实现商品搜索

    好好学习,天天向上 本文已收录至我的Github仓库DayDayUP:github.com/RobodLee/DayDayUP,欢迎Star,更多文章请前往:目录导航 畅购商城(一):环境搭建 畅购商 ...

  9. ASP.NET MVC5 网站开发实践(二) Member区域–管理列表、回复及删除

    本来想接着上次把这篇写完的,没想到后来工作的一些事落下了,放假了赶紧补上. 目录: ASP.NET MVC5 网站开发实践 - 概述 ASP.NET MVC5 网站开发实践(一) - 项目框架 ASP ...

  10. ASP.NET MVC5 网站开发实践(二) Member区域–我的咨询列表及添加咨询

    上次把咨询的架构搭好了,现在分两次来完成咨询:1.用户部分,2管理部分.这次实现用户部分,包含两个功能,查看我的咨询和进行咨询. 目录: ASP.NET MVC5 网站开发实践 - 概述 ASP.NE ...

随机推荐

  1. Spring Ioc 常用注解

    在开发中spring ioc的配置方式有多种方式,常用的一般都是byName.byType .以及其自动装配可以查看http://www.cnblogs.com/gubai/p/9140840.htm ...

  2. Oracle中特殊的变量类型

    1.%TYPE 允许用户动态地将数据库中某一列的数据类型与PL/SQL中某个变量关联.语法如下: variable_name table.column%TYPE   2.%ROWTYPE 允许用户定义 ...

  3. centos7安装ceph-luminous(1 mon+2 osd)

    说明:由于环境有限,这里只是用一台机器 一.部署环境 VMware Workstation 10 centos7 二.主机配置 主机名 ip cpu ram master 192.168.137.10 ...

  4. golang中数组指针和指针数组的区别

    func test(){ x,y := 1, 2 var arr = [...]int{5:2} //数组指针 var pf *[6]int = &arr //指针数组 pfArr := [. ...

  5. SSM+MyBatis框架详解

  6. DAO和service的解释

    转自:http://blog.sina.com.cn/s/blog_4b1452dd0102wvox.html 我们都知道有了Hibernate后,单独对数据的POJO封装以及XML文件要耗损掉一个类 ...

  7. Django+easyui 快速开发

    Django的使用我们可以查看上一篇博客,今天我们要在Django中使用easyui快速开发,在我们安装好Django, 我们可以道改地址那一下easyui 官方API文档(http://downlo ...

  8. LeetCode刷题:第一题 两数之和

    从今天开始刷LeetCode 第一题:两数之和 题目描述: 给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那 两个 整数,并返回他们的数组下标. 你可以假设每种 ...

  9. 常用maven仓库

    常用Maven仓库网址:http://mvnrepository.com/http://search.maven.org/http://repository.sonatype.org/content/ ...

  10. 【.NET Core项目实战-统一认证平台】第二章网关篇-定制Ocelot来满足需求

    [.NET Core项目实战-统一认证平台]开篇及目录索引 这篇文章,我们将从Ocelot的中间件源码分析,目前Ocelot已经实现那些功能,还有那些功能在我们实际项目中暂时还未实现,如果我们要使用这 ...