[TOC]
> * 檢索可以:
* 全文搜索的數據首先會被analysis分析器分詞解析成倒排索引,進而存儲成為文檔,以便于全文搜索。
1. 結構化查詢:在某字段精準的結構化匹配查詢(類似于關系型數據庫)
2. 全文搜索:使用文檔的所有字段匹配某個關鍵字,然后按照匹配的相似程度排序輸出搜索結果
3. 結合以上兩條搜索方式
> * search api
1. 簡單風格:查詢字符串(query string)將所有參數通過查詢字符串定義
2. 結構化查詢語句(DSL):使用json表示完整的請求體
> * elasticsearch的數據類型
1. 確切值:如名字,日期等確定的唯一的詞或短語(數值、日期。。。)
2. 全文文本:人類語言書寫的文章,郵件內容等,為了對全文文本進行分析,elasticsearch會對文本進行分析(分詞),形成倒排索引(字符串)。
### 1. 中文分詞器
-----------------------------------------------------------------------------------------------------------------------------------------------
1.安裝
~~~
./elasticsearch-plugin install https://github.com/medcl/elasticsearch-analysis-ik/releases/download/v5.5.2/elasticsearch-analysis-ik-5.5.2.zip
~~~
2.創建索引
`curl -XPUT http://192.168.56.130:9200/index`
3.設置屬性
~~~
curl -XPOST http://192.168.56.130:9200/index/fulltext/_mapping -d'
{
"properties": {
"content": {
"type": "text",
"analyzer": "ik_max_word",
"search_analyzer": "ik_max_word"
}
}
}'
~~~
4. 插入數據
~~~
curl -XPOST http://192.168.56.130:9200/index/fulltext/1 -d'
{"content":"美國留給伊拉克的是個爛攤子嗎"}'
curl -XPOST http://192.168.56.130:9200/index/fulltext/2 -d'
{"content":"公安部:各地校車將享最高路權"}'
curl -XPOST http://192.168.56.130:9200/index/fulltext/3 -d'
{"content":"中韓漁警沖突調查:韓警平均每天扣1艘中國漁船"}'
curl -XPOST http://192.168.56.130:9200/index/fulltext/4 -d'
{"content":"中國駐洛杉磯領事館遭亞裔男子槍擊 嫌犯已自首"}'
~~~
5.查詢數據
~~~
curl -XPOST http://192.168.56.130:9200/index/fulltext/_search?pretty -d'
{
"query" : { "match" : { "content" : "中國" }},
"highlight" : {
"pre_tags" : ["<tag1>", "<tag2>"],
"post_tags" : ["</tag1>", "</tag2>"],
"fields" : {
"content" : {}
}
}
}'
~~~
6. 查詢類型

### 2. java 客戶端
1. pom.xml
~~~
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.aixin.elasticsearch</groupId>
<artifactId>elasticearchclient</artifactId>
<version>1.0</version>
<dependencies>
<dependency>
<groupId>org.elasticsearch.client</groupId>
<artifactId>transport</artifactId>
<version>5.5.2</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.8.2</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
<dependency>
<groupId>org.elasticsearch</groupId>
<artifactId>elasticsearch</artifactId>
<version>5.5.1</version>
</dependency>
<dependency>
<groupId>org.elasticsearch.client</groupId>
<artifactId>x-pack-transport</artifactId>
<version>5.5.1</version>
</dependency>
<dependency>
<groupId>org.elasticsearch.client</groupId>
<artifactId>rest</artifactId>
<version>5.5.1</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.1</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<version>2.5.5</version>
<configuration>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
</configuration>
<executions>
<execution>
<id>make-assembly</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<executions>
<execution>
<id>attach-sources</id>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
~~~
### 2.1 node 自動探查
1. client集群自動探查
> 1. 默認情況下,是根據我們手動指定的所有節點,依次輪詢這些節點,來發送各種請求的,如下面的代碼,我們可以手動為client指定多個節點
~~~
TransportClient client = new PreBuiltTransportClient(settings)
.addTransportAddress(new InetSocketTransportAddress(InetAddress.getByName("localhost1"), 9300))
.addTransportAddress(new InetSocketTransportAddress(InetAddress.getByName("localhost2"), 9300))
.addTransportAddress(new InetSocketTransportAddress(InetAddress.getByName("localhost3"), 9300));
~~~
>2. 但是問題是,如果我們有成百上千個節點呢?為了對來自客戶端的請求可以負載均衡,難道也要這樣手動添加嗎?
> 3. es client提供了一種集群節點自動探查的功能,打開這個自動探查機制以后,es client會根據我們手動指定的幾個節點連接過去,然后通過集群狀態`自動獲取`當前集群中的`所有data node`,然后用這份完整的列表更新自己內部要發送請求的node list。默認每隔5秒鐘,就會更新一次node list。
> 但是注意,es cilent是不會將Master node納入node list的,因為要避免給master node發送搜索等請求。
> 這樣的話,我們其實直接就指定幾個master node,或者1個node就好了,client會自動去探查集群的所有節點,而且每隔5秒還會自動刷新。非常棒。
~~~
Settings settings = Settings.builder()
.put("client.transport.sniff", true).build(); # 開啟自動探查
TransportClient client = new PreBuiltTransportClient(settings);
~~~
* 使用上述的settings配置,將client.transport.sniff設置為true即可打開集群節點自動探查功能
2. 代碼
~~~
package com.aixin.elasticsearch.client;
import org.apache.lucene.index.Fields;
import org.apache.lucene.index.Terms;
import org.apache.lucene.index.TermsEnum;
import org.elasticsearch.action.delete.DeleteResponse;
import org.elasticsearch.action.get.GetResponse;
import org.elasticsearch.action.search.SearchRequestBuilder;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.action.search.SearchType;
import org.elasticsearch.action.termvectors.TermVectorsRequest;
import org.elasticsearch.action.termvectors.TermVectorsResponse;
import org.elasticsearch.client.transport.TransportClient;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.transport.InetSocketTransportAddress;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.query.TermQueryBuilder;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
import org.elasticsearch.xpack.client.PreBuiltXPackTransportClient;
import java.io.IOException;
import java.net.InetAddress;
import java.util.*;
import static org.elasticsearch.index.query.QueryBuilders.matchQuery;
/**
* Created by dailin on 2017/8/31.
*/
public class ElasticsearchClient {
private static ElasticsearchClient elasticsearchClient = null;
private static TransportClient client = null;
private ElasticsearchClient(String host,String user,String password) {
try {
Settings settings = Settings.builder()
.put("xpack.security.user", user+":"+password)
.put("cluster.name", "e-cluster").build();
client = new PreBuiltXPackTransportClient(settings)
.addTransportAddress(new InetSocketTransportAddress(InetAddress.getByName(host), 9300));
} catch (Exception e) {
e.printStackTrace();
}
}
public static ElasticsearchClient getInstance(String host,String user,String password) {
if (elasticsearchClient == null) {
synchronized (ElasticsearchClient.class) {
if (elasticsearchClient == null) {
elasticsearchClient = new ElasticsearchClient(host,user,password);
}
}
}
return elasticsearchClient;
}
/**
* 獲取文檔
* @param index 索引
* @param type 類型
* @param id 文檔id
* @return
*/
public Document get(String index, String type, String id) {
Document document = new Document(index,type,id);
Map<String, String> result = new HashMap<String, String>();
GetResponse response = client.prepareGet(index, type, id).get();
Map<String, Object> source = response.getSource();
for (Map.Entry<String, Object> map : source.entrySet()) {
document.puToFile(map.getKey(), map.getValue().toString());
}
return document;
}
/**
* 刪除文檔
* @param index 索引
* @param type 類型
* @param id 文檔id
*/
public void deleteById(String index, String type, String id) {
DeleteResponse dr = client.prepareDelete(index, type, id).get();
}
public List<String> matchs(String index, String field, String text) {
List<String> result = new ArrayList<String>();
QueryBuilder qb = matchQuery(field, text);
SearchResponse response = client.prepareSearch(index)
.setSearchType(SearchType.QUERY_THEN_FETCH)
.setQuery(qb)// 設置字段和值
.get();
SearchHits hits = response.getHits();
SearchHit[] hits1 = hits.getHits();
for (SearchHit sh : hits1) {
for (Map.Entry<String, Object> map : sh.getSource().entrySet()) {
result.add(map.getValue().toString());
}
}
return result;
}
/**
* 文檔詞頻統計
* @param index
* @param type
* @param id
* @return Map<詞語,頻率>
* @throws IOException
*/
public Map<String,Integer> termVectos(String index, String type, String id,String field) throws IOException {
TermVectorsRequest.FilterSettings filterSettings = new TermVectorsRequest.FilterSettings();
filterSettings.minWordLength = 2;
TermVectorsResponse resp = client.prepareTermVectors(index, type, id)
.setFilterSettings(filterSettings)
.setSelectedFields(field)
.execute().actionGet();
//獲取字段
Fields fields = resp.getFields();
Iterator<String> iterator = fields.iterator();
Map<String,Integer> result = new HashMap<String, Integer>();
while (iterator.hasNext()){
String dfield = iterator.next();
Terms terms = fields.terms(dfield); //獲取字段對應的terms
TermsEnum termsEnum = terms.iterator(); //termsEnum包含詞語統計信息
while (termsEnum.next() != null){
String word = termsEnum.term().utf8ToString();
int freq = termsEnum.postings(null,120).freq();
result.put(word,freq);
}
}
return result;
}
/**
* 字段之上精準查詢
* @param index
* @param type
* @param field
* @param text
* @return
*/
public List<String> termQuery( String index, String type,String field,String text) {
TermQueryBuilder termQueryBuilder = QueryBuilders.termQuery(field, text);
SearchRequestBuilder searchRequestBuilder = client.prepareSearch(index)
.setTypes(type)
.setQuery(termQueryBuilder);
SearchResponse searchResponse = searchRequestBuilder.get();
SearchHit[] hits = searchResponse.getHits().getHits();
List<String> values = new ArrayList<String>();
for (SearchHit hit : hits) {
for (Map.Entry<String, Object> map : hit.getSource().entrySet()) {
values.add(map.getValue().toString());
}
}
return values;
}
/**
* 分組聚合,對應操作一節中7。查詢聚合(多次分組)
*/
public void doubleAggSearch() {
SearchResponse searchResponse = client.prepareSearch("company")
.addAggregation(AggregationBuilders.terms("group_by_country").field("country")
.subAggregation(AggregationBuilders
.dateHistogram("group_by_join_date")
.field("join_date")
.dateHistogramInterval(DateHistogramInterval.YEAR)
.subAggregation(AggregationBuilders.avg("avg_age").field("age")))
)
.execute().actionGet();
Map<String, Aggregation> aggrMap = searchResponse.getAggregations().asMap();
StringTerms groupByCountry = (StringTerms) aggrMap.get("group_by_country");
Iterator<StringTerms.Bucket> groupByCountryBucketIterator = groupByCountry.getBuckets().iterator(); //country 組
while (groupByCountryBucketIterator.hasNext()) {
StringTerms.Bucket groupByCountryBucket = groupByCountryBucketIterator.next();
System.out.println(groupByCountryBucket.getKey() + ":" + groupByCountryBucket.getDocCount());
Histogram groupByJoinDate = (Histogram) groupByCountryBucket.getAggregations().asMap().get("group_by_join_date"); //獲取country內日期組
Iterator<? extends Histogram.Bucket> groupByJoinDateBucketIterator = groupByJoinDate.getBuckets().iterator();
while (groupByJoinDateBucketIterator.hasNext()) {
org.elasticsearch.search.aggregations.bucket.histogram.Histogram.Bucket groupByJoinDateBucket = groupByJoinDateBucketIterator.next();
System.out.println(groupByJoinDateBucket.getKey() + ":" + groupByJoinDateBucket.getDocCount());
Avg avg = (Avg) groupByJoinDateBucket.getAggregations().asMap().get("avg_age"); //日期組內平均年齡
System.out.println(avg.getValue());
}
}
}
/**
* 全文搜索
* @param index 索引
* @param field 字段
* @param text 查詢語句
* @return Document對象
*/
public List<Document> match(String index, String field, String text) {
List<Document> result = new ArrayList<Document>();
QueryBuilder qb = matchQuery(field, text);
SearchResponse response = client.prepareSearch(index)
.setSearchType(SearchType.QUERY_THEN_FETCH)
.setQuery(qb)// 設置字段和值
.get();
SearchHits hits = response.getHits();
SearchHit[] searchHits = hits.internalHits();
for (SearchHit hist : searchHits){
Document document = new Document(hist.getIndex(),hist.getType(),hist.getId());
result.add(document);
Map<String, Object> source = hist.getSource();
Set<Map.Entry<String, Object>> entries = source.entrySet();
for (Map.Entry<String,Object> v : entries){
document.puToFile(v.getKey(),v.getValue().toString());
}
}
return result;
}
/**
* 標記與查詢語句相匹配的詞語
* @param index 索引
* @param field 字段
* @param text 查詢語句
* @return 文檔(Document)對象
*/
public List<Document> matchHighLight(String index, String field, String text) {
List<Document> result = new ArrayList<Document>();
HighlightBuilder highlightBuilder = new HighlightBuilder();
highlightBuilder.postTags("<mark>");
highlightBuilder.preTags("</mark>");
highlightBuilder.field(field);
QueryBuilder qb = matchQuery(field, text);
SearchResponse response = client.prepareSearch(index)
.highlighter(highlightBuilder)
.setSearchType(SearchType.QUERY_THEN_FETCH)
.setQuery(qb)// 設置字段和值
.get();
SearchHits hits = response.getHits();
SearchHit[] searchHits = hits.internalHits();
for (SearchHit hist : searchHits){
Map<String, HighlightField> highlightFields = hist.getHighlightFields();
Set<Map.Entry<String, HighlightField>> entries1 = highlightFields.entrySet();
for (Map.Entry<String,HighlightField> v : entries1){
Document document = new Document(hist.getIndex(),hist.getType(),hist.getId());
document.puToFile( v.getKey(),v.getValue().toString());
result.add(document);
}
}
return result;
}
}
~~~
### 2.2 更新字段
~~~
package com.roncoo.es.senior;
import java.net.InetAddress;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.update.UpdateRequest;
import org.elasticsearch.action.update.UpdateResponse;
import org.elasticsearch.client.transport.TransportClient;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.transport.InetSocketTransportAddress;
import org.elasticsearch.common.xcontent.XContentFactory;
import org.elasticsearch.transport.client.PreBuiltTransportClient;
public class UpsertCarInfoApp {
@SuppressWarnings({ "unchecked", "resource" })
public static void main(String[] args) throws Exception {
Settings settings = Settings.builder()
.put("cluster.name", "e-cluster")
.put("client.transport.sniff", true)
.build();
TransportClient client = new PreBuiltTransportClient(settings)
.addTransportAddress(new InetSocketTransportAddress(InetAddress.getByName("192.168.56.130"), 9300));
IndexRequest indexRequest = new IndexRequest("car_shop", "cars", "1")
.source(XContentFactory.jsonBuilder()
.startObject()
.field("brand", "寶馬")
.field("name", "寶馬320")
.field("price", 310000)
.field("produce_date", "2017-01-01")
.endObject());
UpdateRequest updateRequest = new UpdateRequest("car_shop", "cars", "1")
.doc(XContentFactory.jsonBuilder()
.startObject()
.field("price", 320000)
.endObject())
.upsert(indexRequest); //如果有這個index更新,沒有就插入
UpdateResponse updateResponse = client.update(updateRequest).get();
System.out.println(updateResponse.getVersion());
client.close();
}
}
~~~
- Docker
- 什么是docker
- Docker安裝、組件啟動
- docker網絡
- docker命令
- docker swarm
- dockerfile
- mesos
- 運維
- Linux
- Linux基礎
- Linux常用命令_1
- Linux常用命令_2
- ip命令
- 什么是Linux
- SELinux
- Linux GCC編譯警告:Clock skew detected. 錯誤解決辦法
- 文件描述符
- find
- 資源統計
- LVM
- Linux相關配置
- 服務自啟動
- 服務器安全
- 字符集
- shell腳本
- shell命令
- 實用腳本
- shell 數組
- 循環與判斷
- 系統級別進程開啟和停止
- 函數
- java調用shell腳本
- 發送郵件
- Linux網絡配置
- Ubuntu
- Ubuntu發送郵件
- 更換apt-get源
- centos
- 防火墻
- 虛擬機下配置網絡
- yum重新安裝
- 安裝mysql5.7
- 配置本地yum源
- 安裝telnet
- 忘記root密碼
- rsync+ crontab
- Zabbix
- Zabbix監控
- Zabbix安裝
- 自動報警
- 自動發現主機
- 監控MySQL
- 安裝PHP常見錯誤
- 基于nginx安裝zabbix
- 監控Tomcat
- 監控redis
- web監控
- 監控進程和端口號
- zabbix自定義監控
- 觸發器函數
- zabbix監控mysql主從同步狀態
- Jenkins
- 安裝Jenkins
- jenkins+svn+maven
- jenkins執行shell腳本
- 參數化構建
- maven區分環境打包
- jenkins使用注意事項
- nginx
- nginx認證功能
- ubuntu下編譯安裝Nginx
- 編譯安裝
- Nginx搭建本地yum源
- 文件共享
- Haproxy
- 初識Haproxy
- haproxy安裝
- haproxy配置
- virtualbox
- virtualbox 復制新的虛擬機
- ubuntu下vitrualbox安裝redhat
- centos配置雙網卡
- 配置存儲
- Windows
- Windows安裝curl
- VMware vSphere
- 磁盤管理
- 增加磁盤
- gitlab
- 安裝
- tomcat
- Squid
- bigdata
- FastDFS
- FastFDS基礎
- FastFDS安裝及簡單實用
- api介紹
- 數據存儲
- FastDFS防盜鏈
- python腳本
- ELK
- logstash
- 安裝使用
- kibana
- 安準配置
- elasticsearch
- elasticsearch基礎_1
- elasticsearch基礎_2
- 安裝
- 操作
- java api
- 中文分詞器
- term vector
- 并發控制
- 對text字段排序
- 倒排和正排索引
- 自定義分詞器
- 自定義dynamic策略
- 進階練習
- 共享鎖和排它鎖
- nested object
- 父子關系模型
- 高亮
- 搜索提示
- Redis
- redis部署
- redis基礎
- redis運維
- redis-cluster的使用
- redis哨兵
- redis腳本備份還原
- rabbitMQ
- rabbitMQ安裝使用
- rpc
- RocketMQ
- 架構概念
- 安裝
- 實例
- 好文引用
- 知乎
- ACK
- postgresql
- 存儲過程
- 編程語言
- 計算機網絡
- 基礎_01
- tcp/ip
- http轉https
- Let's Encrypt免費ssl證書(基于haproxy負載)
- what's the http?
- 網關
- 網絡IO
- http
- 無狀態網絡協議
- Python
- python基礎
- 基礎數據類型
- String
- List
- 遍歷
- Python基礎_01
- python基礎_02
- python基礎03
- python基礎_04
- python基礎_05
- 函數
- 網絡編程
- 系統編程
- 類
- Python正則表達式
- pymysql
- java調用python腳本
- python操作fastdfs
- 模塊導入和sys.path
- 編碼
- 安裝pip
- python進階
- python之setup.py構建工具
- 模塊動態導入
- 內置函數
- 內置變量
- path
- python模塊
- 內置模塊_01
- 內置模塊_02
- log模塊
- collections
- Twisted
- Twisted基礎
- 異步編程初探與reactor模式
- yield-inlineCallbacks
- 系統編程
- 爬蟲
- urllib
- xpath
- scrapy
- 爬蟲基礎
- 爬蟲種類
- 入門基礎
- Rules
- 反反爬蟲策略
- 模擬登陸
- problem
- 分布式爬蟲
- 快代理整站爬取
- 與es整合
- 爬取APP數據
- 爬蟲部署
- collection for ban of web
- crawlstyle
- API
- 多次請求
- 向調度器發送請求
- 源碼學習
- LinkExtractor源碼分析
- 構建工具-setup.py
- selenium
- 基礎01
- 與scrapy整合
- Django
- Django開發入門
- Django與MySQL
- java
- 設計模式
- 單例模式
- 工廠模式
- java基礎
- java位移
- java反射
- base64
- java內部類
- java高級
- 多線程
- springmvc-restful
- pfx數字證書
- 生成二維碼
- 項目中使用log4j
- 自定義注解
- java發送post請求
- Date時間操作
- spring
- 基礎
- spring事務控制
- springMVC
- 注解
- 參數綁定
- springmvc+spring+mybatis+dubbo
- MVC模型
- SpringBoot
- java配置入門
- SpringBoot基礎入門
- SpringBoot web
- 整合
- SpringBoot注解
- shiro權限控制
- CommandLineRunner
- mybatis
- 靜態資源
- SSM整合
- Aware
- Spring API使用
- Aware接口
- mybatis
- 入門
- mybatis屬性自動映射、掃描
- 問題
- @Param 注解在Mybatis中的使用 以及傳遞參數的三種方式
- mybatis-SQL
- 逆向生成dao、model層代碼
- 反向工程中Example的使用
- 自增id回顯
- SqlSessionDaoSupport
- invalid bound statement(not found)
- 脈絡
- beetl
- beetl是什么
- 與SpringBoot整合
- shiro
- 什么是shiro
- springboot+shrio+mybatis
- 攔截url
- 枚舉
- 圖片操作
- restful
- java項目中日志處理
- JSON
- 文件工具類
- KeyTool生成證書
- 兼容性問題
- 開發規范
- 工具類開發規范
- 壓縮圖片
- 異常處理
- web
- JavaScript
- 基礎語法
- 創建對象
- BOM
- window對象
- DOM
- 閉包
- form提交-文件上傳
- td中內容過長
- 問題1
- js高級
- js文件操作
- 函數_01
- session
- jQuery
- 函數01
- data()
- siblings
- index()與eq()
- select2
- 動態樣式
- bootstrap
- 表單驗證
- 表格
- MUI
- HTML
- iframe
- label標簽
- 規范編程
- layer
- sss
- 微信小程序
- 基礎知識
- 實踐
- 自定義組件
- 修改自定義組件的樣式
- 基礎概念
- appid
- 跳轉
- 小程序發送ajax
- 微信小程序上下拉刷新
- if
- 工具
- idea
- Git
- maven
- svn
- Netty
- 基礎概念
- Handler
- SimpleChannelInboundHandler 與 ChannelInboundHandler
- 網絡編程
- 網絡I/O
- database
- oracle
- 游標
- PLSQL Developer
- mysql
- MySQL基準測試
- mysql備份
- mysql主從不同步
- mysql安裝
- mysql函數大全
- SQL語句
- 修改配置
- 關鍵字
- 主從搭建
- centos下用rpm包安裝mysql
- 常用sql
- information_scheme數據庫
- 值得學的博客
- mysql學習
- 運維
- mysql權限
- 配置信息
- 好文mark
- jsp
- jsp EL表達式
- C
- test