LibLinear使用及與Lib的區別
以下為一位網友採用liblinear進行資料分類的實驗效能說明“
”今天試用了以下liblinear,速度很快(快到我沒有想到),
我的實驗資料:
訓練集:21504 * 1500(1500是樣本的數量,21504是維度)
測試集:21504 * 2985
速度用秒來衡量,20次實驗總共不到2分鐘。
同樣的問題我用了libsvm實驗速度上相差太大,libsvm實驗5次,每次將近10分鐘,時間是其次,發現一個問題就是,libsvm比liblinear的結果相差1個百分點,沒有讀liblinear的文章,不知道問題出在那個地方,libsvm我直接用的預設引數,線性模型。這樣必然引起一個問題,如果我想評價線性模型和非線性模型的效能,我不可能一個用liblinear一個用libsvm,如果兩個都用libsvm,報告的效能肯定有一些問題。
所以如果你的問題維度很大(線性模型就有非常好的效能),不妨考慮liblinear.
大致看了一下libsvm和liblinear的說明文件,發現一個問題就是線上性問題上兩者的目標函式就不一樣,所以效能上的差異是正常的,應該說如果優化同一樣的目標函式兩者效能應該會差不多,但是速度很明顯,liblinear快很多。
更多:
http://blog.163.com/[email protected]/blog/static/23522694201312124221734/
http://blog.sina.com.cn/s/blog_5b29caf701015ra0.html
http://blog.sina.com.cn/s/blog_5b29caf7010127vh.html
2、快速入門
按“安裝”這一章節的說明來安裝LIBLINEAR。安裝完成後,就會得到兩個程式,train和predict,分別是用來訓練分類器和測試分類器的兩個程式。
對於資料格式。請檢視LIBSVM的README檔案。需要注意的是,特徵的索引是從1開始的,而不是0 。
這個包還包含了一個例子,分類的資料是`heart_scale'。
執行`trainheart_scale',train程式就會讀取對應的訓練資料,然後輸出訓練好的分類器模型`heart_scale.model'。如果你有一個測試集,命名為heart_scale.t,那麼你可以執行`predict heart_scale.t heart_scale.model output'來測試該分類器的識別準確率。這個output檔案包含了分類器對測試集中每個樣本預測得到的對應的類標籤。
為了獲得好的效能,有時候需要先對資料進行scale。可以檢視LIBSVM的`svm-scale'程式來獲得相關的資訊。對於非常大和稀疏的資料,使用引數`-l 0'來保持訓練中資料的稀疏性。
建議的訓練步驟(來源於libSVM,感覺對這個也有幫助,所以也標記在這):
1)將我們的訓練資料和測試資料轉換為該SVM軟體包支援的格式;
2)對資料進行簡單的尺度化scale;
3)先考慮用RBF核;
4)使用交叉檢驗方法去尋找最優的引數C和γ;
5)使用找到的最好的引數C和γ來訓練整個訓練集;
6)在測試集上測試。
3、安裝(略)
4、程式train的用法
用法:train [options] training_set_file [model_file]
options:
-s type : 對於多分類,指定使用的分類器(預設是1):
0 -- L2-regularized logistic regression(primal)
1 -- L2-regularized L2-loss support vectorclassification (dual)
2 -- L2-regularized L2-loss support vectorclassification (primal)
3 -- L2-regularized L1-loss support vectorclassification (dual)
4 -- support vector classification by Crammerand Singer
5 -- L1-regularized L2-loss support vectorclassification
6 -- L1-regularized logistic regression
7 -- L2-regularized logistic regression (dual)
對於迴歸:
11-- L2-regularized L2-loss support vector regression (primal)
12-- L2-regularized L2-loss support vector regression (dual)
13-- L2-regularized L1-loss support vector regression (dual)
-c cost : 設定引數 C(預設是1)
-p epsilon : 設定epsilon-SVR的損失函式的引數epsilon(預設是0.1)
-e epsilon : 設定迭代終止條件的容忍度tolerance
-s0 and 2
|f'(w)|_2<= eps*min(pos,neg)/l*|f'(w0)|_2,
f是primal 函式,pos/neg 是對應的正樣本和負樣本數目(預設是0.01)
-s11
|f'(w)|_2<= eps*|f'(w0)|_2 (預設是0.001)
-s1, 3, 4 and 7
Dualmaximal violation <= eps; 和 libsvm相似(預設是0.1)
-s5 and 6
|f'(w)|_inf<= eps*min(pos,neg)/l*|f'(w0)|_inf,
f是primal 函式,pos/neg 是對應的正樣本和負樣本數目(預設是0.01)
-s12 and 13\n"
|f'(alpha)|_1<= eps |f'(alpha0)|,
f是dual(對偶)函式(預設是0.1)
-B bias : 如果bias >= 0,那樣樣本x變為[x; bias],如果小於0,則不增加bias項(預設是-1)
-wi weight: 調整不同類別的引數C的權值(具體見README)
-v n: n-fold交叉檢驗模式。它隨機的將資料劃分為n個部分,然後計算它們的交叉檢驗準確率。
-q : 安靜模式(無輸出資訊)
Formulations公式(優化問題):
For L2-regularized logistic regression (-s0), we solve
min_w w^Tw/2 + C\sum log(1 + exp(-y_i w^Tx_i))
For L2-regularized L2-loss SVC dual (-s 1),we solve
min_alpha 0.5(alpha^T (Q + I/2/C) alpha) - e^T alpha
s.t. 0 <= alpha_i,
For L2-regularized L2-loss SVC (-s 2), wesolve
min_w w^Tw/2 + C\sum max(0, 1- y_i w^Tx_i)^2
For L2-regularized L1-loss SVC dual (-s 3),we solve
min_alpha 0.5(alpha^T Q alpha) - e^T alpha
s.t. 0 <= alpha_i <= C,
For L1-regularized L2-loss SVC (-s 5), wesolve
min_w \sum |w_j|+ C \sum max(0, 1- y_i w^Tx_i)^2
For L1-regularized logistic regression (-s6), we solve
min_w \sum |w_j|+ C \sum log(1 + exp(-y_i w^Tx_i))
For L2-regularized logistic regression (-s7), we solve
min_alpha 0.5(alpha^T Q alpha) + \sumalpha_i*log(alpha_i) + \sum (C-alpha_i)*log(C-alpha_i) - a constant
s.t. 0 <= alpha_i <= C,
where, Q is a matrix with Q_ij = y_i y_jx_i^T x_j.
For L2-regularized L2-loss SVR (-s 11), wesolve
min_w w^Tw/2 + C\sum max(0, |y_i-w^Tx_i|-epsilon)^2
For L2-regularized L2-loss SVR dual (-s12), we solve
min_beta 0.5(beta^T (Q + lambda I/2/C) beta) - y^Tbeta + \sum |beta_i|
For L2-regularized L1-loss SVR dual (-s13), we solve
min_beta 0.5(beta^T Q beta) - y^T beta + \sum |beta_i|
s.t. -C <= beta_i <= C,
where, Q is a matrix with Q_ij = x_i^T x_j.
如果bias >= 0,那麼w變為[w;w_{n+1}] ,x 變為[x; bias]。
primal-dual的關係表明了-s 1 和 -s 2學習到的是同樣的模型。-s0 和 -s 7,-s 11 和 -s 12也是。
我們實現了一對多的多分類方法。在訓練i類和non_i類的時候,它們的引數C分別是(weight from -wi)*C和C。如果只有兩類,我們只訓練一個模型。這時候使用weight1*C和weight2*C。看下面的例子。
我們還實現了多類SVM byCrammer and Singer (-s 4):
min_{w_m, \xi_i} 0.5 \sum_m ||w_m||^2 + C \sum_i \xi_i
s.t. w^T_{y_i} x_i - w^T_m x_i>= \e^m_i - \xi_i \forall m,i
where, e^m_i = 0 if y_i = m,
e^m_i = 1 if y_i != m,
這裡我們解dual 問題:
min_{\alpha} 0.5 \sum_m ||w_m(\alpha)||^2 + \sum_i \sum_me^m_i alpha^m_i
s.t. \alpha^m_i <= C^m_i\forall m,i , \sum_m \alpha^m_i=0 \forall i
where, w_m(\alpha) = \sum_i \alpha^m_i x_i,
and C^m_i = C if m = y_i,
C^m_i = 0 if m != y_i.
5、程式predict的用法
用法:predict [options] test_file model_file output_file
options:
-b probability_estimates: 是否輸出概率估計。預設是0,不輸出。只對logistic迴歸有用
-q : 安靜模式(無輸出資訊)
需要注意的是-b只在預測階段用到。這個和LIBSVM不同。
6、例子
> train data_file
預設引數的時候,訓練的是L2損失函式的線性SVM
> train -s 0 data_file
-s 0指定訓練一個logistic迴歸模型
> train -v 5 -e 0.001 data_file
-v 5指定5-fold的交叉檢驗模式。-e 0.001指定一個比預設值更小的迭代停止容忍度。
> train -c 10 -w1 2 -w2 5 -w3 2four_class_data_file
-c 10指定引數C是10,-w1 2指定第一類的權值w是2,這時候對應的C是w*C,其他同。例如我們要訓練四類。-w1 2 -w2 5 -w3 2分別指定了類1的C=w*C=2*10=20,類2的C=w*C=5*10=50,類3同。類4沒有指定,所以是C。其他對應的負類的C都是10 。(我們要訓練四類的分類器,就需要四個二分類器,正負樣本各需要一個引數C)
Train four classifiers:
positive negative Cp Cn
class 1 class 2,3,4. 20 10
class 2 class 1,3,4. 50 10
class 3 class 1,2,4. 20 10
class 4 class 1,2,3. 10 10
> train -c 10 -w3 1 -w2 5two_class_data_file
如果只有兩類,我們只訓練一個模型。這時候兩類的C值分別是10 和 50。
> predict -b 1 test_file data_file.modeloutput_file
-b 1指定輸出每類估計得到的概率值。只對logistic迴歸有效。
七、庫的用法
1、函式train()
-Function: model* train(const struct problem *prob,
const struct parameter *param);
這個函式根據給定的訓練資料和引數構造一個線性分類器或者回歸模型並返回。
2、結構體struct problem
結構體structproblem 描述我們要求解的問題:
struct problem
{
int l, n;
int *y;
struct feature_node **x;
double bias;
};
l表示訓練資料的個數。如果bias>= 0,那麼我們會在每個樣本的末尾新增一個額外的值,這時候,樣本x變為[x; bias]。n表示特徵(樣本)的維數(包括bias)。y是儲存了目標值(期望輸出或者樣本標籤)的陣列。x是一個指標陣列,每個元素指向一個儲存了一個樣本的稀疏表示的陣列(結構體feature_node的陣列)。
例如,如果我們有以下的訓練資料:
LABEL ATTR1 ATTR2 ATTR3 ATTR4 ATTR5
----- ----- ----- ----- ----- -----
1 0 0.1 0.2 0 0
2 0 0.1 0.3 -1.2 0
1 0.4 0 0 0 0
2 0 0.1 0 1.4 0.5
3 -0.1 -0.2 0.1 1.1 0.1
還有bias = 1,那這個問題描述的結構體struct problem就可以描述為:
l= 5共五個樣本
n= 6 特徵的維數5+1=6
y-> 1 2 1 2 3 每個樣本對應的標籤值
x-> [ ] -> (2,0.1) (3,0.2) (6,1) (-1,?)
[ ] -> (2,0.1) (3,0.3) (4,-1.2) (6,1) (-1,?)
[ ] -> (1,0.4) (6,1) (-1,?)
[ ] -> (2,0.1) (4,1.4) (5,0.5) (6,1) (-1,?)
[ ] -> (1,-0.1) (2,-0.2) (3,0.1) (4,1.1) (5,0.1) (6,1) (-1,?)
x儲存的是每個樣本的稀疏表示,也就是0值就不儲存,只儲存非零值和其對應的索引號。例如第一個樣本,第一個特徵值是0,不管,第二個特徵值是0.1,所以儲存格式為(索引號, 特徵值),也就是(2,0.1)。同理,第三個特徵值是0.2,所以儲存(3,0.2),後面同理。然後通過一個-1的索引號來標記這個樣本的結束。儲存為(-1,?)。
3、結構體struct parameter
結構體structparameter 描述一個線性分類器或者回歸模型的引數:
struct parameter
{
int solver_type;
/* these are for training only*/
double eps; /* stopping criteria */
double C;
int nr_weight;
int *weight_label;
double* weight;
double p;
};
下面介紹下各個成員變數,也就是各個引數,這些引數和在命令列中給train傳入的引數是一致的:
solver_type是solver的型別,可以是以下的其中一種:
L2R_LR,L2R_L2LOSS_SVC_DUAL, L2R_L2LOSS_SVC, L2R_L1LOSS_SVC_DUAL, MCSVM_CS,L1R_L2LOSS_SVC, L1R_LR, L2R_LR_DUAL, L2R_L2LOSS_SVR, L2R_L2LOSS_SVR_DUAL,L2R_L1LOSS_SVR_DUAL.
對於分類器:
L2R_LR L2-regularized logistic regression (primal)
L2R_L2LOSS_SVC_DUAL L2-regularized L2-loss support vector classification (dual)
L2R_L2LOSS_SVC L2-regularized L2-loss support vector classification (primal)
L2R_L1LOSS_SVC_DUAL L2-regularized L1-loss support vector classification (dual)
MCSVM_CS supportvector classification by Crammer and Singer
L1R_L2LOSS_SVC L1-regularized L2-loss support vector classification
L1R_LR L1-regularized logistic regression
L2R_LR_DUAL L2-regularized logistic regression (dual)
對於迴歸模型:
L2R_L2LOSS_SVR L2-regularized L2-loss support vector regression (primal)
L2R_L2LOSS_SVR_DUAL L2-regularized L2-loss support vector regression (dual)
L2R_L1LOSS_SVR_DUAL L2-regularized L1-loss support vector regression (dual)
C是約束violation的代價引數
P是supportvector regression的損失靈敏度
eps是迭代停止條件
nr_weight, weight_label,和 weight 用來改變對一些類的懲罰。預設是1 。這對於使用unbalanced 的輸入資料或者不對稱的誤分類代價來訓練分類器時是很有效的。
nr_weight是陣列weight_label 和 weight的元素個數。每個weight[i]對應weight_label[i]。表示類weight_label[i] 的懲罰會被weight[i]進行尺度化。也就是C= weight_label[i]*C。
如果你不需要對任何類改變懲罰,直接設定nr_weight為0即可。
注意:為了避免錯誤的引數設定,在呼叫train()之前最好先呼叫check_parameter()來檢查引數的正確性。
4、結構體struct model
結構體struct model 儲存訓練得到的模型:
struct model
{
struct parameter param;
int nr_class; /* number of classes */
int nr_feature;
double *w;
int *label; /* label of each class */
double bias;
};
param描述獲得這個模型對應的引數設定。
nr_class 和 nr_feature分別是類和特徵的個數。對於迴歸來說,nr_class = 2
陣列w 的大小是nr_feature*nr_class,是每個特徵對應的權值。對於多分類,我們使用一對多的方法,所以每個特徵都會對應nr_class 個類的特徵權值。權值的儲存通過以下方式來組織:
+------------------+------------------+------------+
| nr_class weights | nr_class weights | ...
| for 1st feature | for 2ndfeature |
+------------------+------------------+------------+
如果bias >= 0,x 變為 [x; bias]。特徵的數目或者維數就會加1,所以陣列w的大小就變為(nr_feature+1)*nr_class。Bias的值儲存在bias這個變數中。
陣列 label 儲存的是類的標籤值。
5、其他函式
-Function: void cross_validation(const problem*prob, const parameter *param,
int nr_fold, double *target);
交叉檢驗函式。資料會被劃分為nr_fold個folds。對每個fold,用剩餘的fold去訓練模型,然後用這個fold來校驗,這個校驗過程得到的預測標籤都會儲存在target這個陣列中。
-Function: double predict(const model *model_, constfeature_node *x);
預測函式。對一個分類模型,傳入一個樣本x,會返回預測到的對應的類。對於一個迴歸模型,就會返回一個由模型計算得到的函式值。
-Function: double predict_values(const struct model*model_,
const struct feature_node *x, double* dec_values);
這個函式得到nr_w個儲存在陣列dec_values的決策值。當使用迴歸模型或者二分類時,nr_w=1。一個例外的情況是Crammer and Singer (-s 4)的多分類SVM。對於其他情況nr_w是類的數目。
我們實現了one-vs-therest一對多的多分類(-s 0,1,2,3,5,6,7)和由Crammer and Singer (-s 4)實現的多分類SVM。該函式返回具有最高決策值的類別。
-Function: double predict_probability(const structmodel *model_,
const struct feature_node *x, double* prob_estimates);
該函式得到nr_class的概率估計值。儲存在prob_estimates陣列中。nr_class可以通過函式get_nr_class獲得。該函式返回最高概率對應的類別。概率的輸出只在logistic迴歸時有效。
-Function: int get_nr_feature(const model *model_);
該函式返回模型的attributes的個數。
-Function: int get_nr_class(const model *model_);
該函式返回模型的類的個數。如果是迴歸模型,返回2.
-Function: void get_labels(const model *model_, int*label);
該函式輸出標籤的名字到一個label的陣列中。
-Function: const char *check_parameter(const structproblem *prob,
const struct parameter *param);
該函式檢測引數的有效性。其需要在train() 和 cross_validation()前呼叫。如果引數有效,那麼返回NULL,否則返回其他的錯誤資訊。
-Function: int save_model(const char*model_file_name,
const struct model *model_);
該函式將模型儲存到一個檔案中。返回0表示成功,-1表示失敗。
- Function:struct model *load_model(const char*model_file_name);
該函式從一個檔案中載入模型。指標為空,表示載入失敗。
-Function: void free_model_content(struct model*model_ptr);
該函式清理記憶體。在一個模型結構的入口處可以呼叫。
-Function: void free_and_destroy_model(struct model**model_ptr_ptr);
該函式幹掉一個模型,並釋放其佔用的記憶體。
-Function: void destroy_param(struct parameter*param);
該函式釋放參數結構體佔用的記憶體。
-Function: void set_print_string_function(void(*print_func)(const char *));
使用者可以指定輸出的格式。set_print_string_function(NULL);將資訊輸入到stdout。
八、編譯Windows下可執行檔案
Windows下可執行檔案在目錄windows下。可以通過VisualC++來編譯得到。編譯過程如下:
1、開啟dos命令列視窗,定位到liblinear目錄下。如果VC++的環境變數還沒設定,敲入以下命令來實現:
"C:\Program Files\Microsoft VisualStudio 10.0\VC\bin\vcvars32.bat"
你可能需要根據你的VC++的版本來稍微修改上述命令。
2、輸入
nmake -f Makefile.win clean all
九、其他介面
MATLAB/OCTAVE 介面檢視matlab目錄下的README檔案。Python介面檢視python'目錄下的README檔案。
十、其他資訊
如果你覺得LIBLINEAR 對你有幫助的話,pleasecite it as:
R.-E. Fan, K.-W. Chang, C.-J. Hsieh, X.-R.Wang, and C.-J. Lin.
LIBLINEAR: A Library for Large LinearClassification, Journal of
Machine Learning Research 9(2008),1871-1874. Software available at
http://www.csie.ntu.edu.tw/~cjlin/liblinear
http://www.csie.ntu.edu.tw/~cjlin/papers/liblinear.pdf
相關推薦
LibLinear使用及與Lib的區別
以下為一位網友採用liblinear進行資料分類的實驗效能說明“ ”今天試用了以下liblinear,速度很快(快到我沒有想到), 我的實驗資料: 訓練集:21504 * 1500(1500是樣本的數量,21504是維度) 測試集:21504 * 2985 速度用秒來衡量,20次實驗總共不到2分
Ioctl使用及與unlocked_ioctl區別
1. Ioctl 用來做什麼? 大部分驅動除了需要具備讀寫裝置的能力外,還需要具備對硬體控制的能力。例如,要求裝置報告錯誤資訊,改變波特率,這些操作常常通過ioctl方法來實現。 1.1 使用者使用方法 在使用者空間,使用ioctl
BDD本質及與ATDD區別
bullet 易懂 一點 view 方便 then nbsp 開發 amp 說起BDD,你會想到什麽? 在剛接觸BDD(Behavior Driven Development,行為驅動開發)的時候,我以為就是用Cucumber這樣的工具來編寫場景用例,從而實現
MySQL中MyISAM與InnoDB區別及選擇,mysql添加外鍵
title 必須 pan 就會 默認 簡化 平臺 兩種 myisam InnoDB:支持事務處理等不加鎖讀取支持外鍵支持行鎖不支持FULLTEXT類型的索引不保存表的具體行數,掃描表來計算有多少行DELETE 表時,是一行一行的刪除InnoDB 把數據和索引存放在表空間裏面
Nginx的alias的用法及與root的區別
nginx root alias 先看官方文檔http://nginx.org/en/docs/http/ngx_http_core_module.html#alias http://nginx.org/en/docs/http/ngx_http_core_module.html#root先看root
js onclick與addEventListener 區別及用法
nbsp scala 一段 onclick 元素 user 不同的 公司 utf-8 addEventListener(建議使用)好比一個監聽容器,這個容器裏面可以裝很多個監聽事件,而且每一個事件都會執行。 onclick 在今天之前我使用這個(onclick)比較多(單純
MySQL中MyISAM與InnoDB區別及選擇
重建 包含 好的 數據 mysql 備份 處理 表空間 種類 InnoDB:支持事務處理等不加鎖讀取支持外鍵支持行鎖不支持FULLTEXT類型的索引不保存表的具體行數,掃描表來計算有多少行DELETE 表時,是一行一行的刪除InnoDB 把數據和索引存放在表空間裏面跨平臺可
WPF TemplateBinding與Binding區別及自定義ImageButton
TemplateBinding與Binding區別在於 1:TemplateBinding只是單方向的資料繫結 2:TemplateBinding不會自動轉換資料型別 這裡用一個自定義ImageButton驗證下第2條: public class ImageButton : Button
hql語言的使用及與sql語言的區別
1. 什麼是hql HQL是Hibernate Query Language的縮寫 查全部 2. hql和sql區別/異同 HQL
Mabitis中的#與$符號區別及用法介紹
一、介紹 mybatis 中使用 Mapper.xml裡面的配置進行 sql 查詢,經常需要動態傳遞引數,例如我們需要根據使用者的姓名來篩選使用者時,sql 如下: ?
http與https區別及https是如何保障安全性
區別: 1、加密:http協議對傳輸的資料不進行加密;https協議對傳輸的資料使用SSL安全協議進行加密,https加密需要CA簽發的證書。 2、埠:http協議使用TCP的80埠;https協議使用TCP的443埠 3、網路分層模型:http可以明確是位於應用層;http
談GPU的作用、原理及與CPU、DSP的區別
GPU是顯示卡的“心臟”,也就相當於CPU在電腦中的作用,它決定了該顯示卡的檔次和大部分效能,同時也是2D顯示卡和3D顯示卡的區別依據。2D顯示晶片在處理3D影象和特效時主要依賴CPU的處理能力,稱為“軟加速”。3D顯示晶片是將三維影象和特效處理功能集中在顯示晶片內,也即所謂
電磁波、無線電、802、WLAN及WiFi的區別與聯絡
一、電磁波、無線電、WLAN和WiFi的關係 電磁波 > 無線電 【+ 可見光】 > WLAN 【+ 電話 】> WiFi 【+藍芽】 參考:https://zh.wikipedia.org/wiki/%E6%97%A0%E7%BA%BF%E7%94%B5 二、80
HttpURLConnection與HttpClient 區別及聯絡
httpclient其實在網路程式設計中,基於java的實現,幾乎都包裝了socket的通訊,然後模擬各總各樣的協議,httpclient其實是模擬瀏覽器發起像伺服器的請求 http://blog.csdn.net/zhliro/article/details
StringBuffer 與 StringBuilder 區別與聯絡及原始碼分析
StringBuffer和StringBuilder的共同點: 1、都是用於操作字串,使用這兩個而不使用String的原因是因為String是Final型別,當對字串操作較多時採用StringBuffer或者StringBuilder。 St
Long物件對比大小及與long基本型別的區別
Long 型別指的是 java.util.Lang 物件,而long基本型別 (注意大小寫) Java中如果使用 == 雙等於比較物件,等於比較的是兩個物件的記憶體地址,也就是比較兩個物件是否是同一個物件, 如果比較兩個Long物件值是否相等,則不可以使用雙等號進行比
MPEG-4與H264區別,編碼及應用
MPEG4於1998年11月公佈,原預計1999 年1月投入使用的國際標準MPEG4不僅是針對一定位元率下的視訊、音訊編碼,更加註重多媒體系統的互動性和靈活性。MPEG專家組的專家們正在為MPEG-4的制定努力工作。MPEG-4標準主要應用於視像電話(V
sizeof與strlen區別及用法
1、sizeof的定義--本身是操作符不是函式 1.1、你可以把操作符理解為內建的,最基礎的函式,它們無法完全被若干個未使用同類型操作符的函式所替代。比如加法運算子,你就不可能寫出一個不用+或-的函式來實現任何情況下的加法功能。 1.2、運
ibatis $與#的區別,及排序問題
在sql配置中#{}#,與${}$ 在ibatis中使用這兩種方式進行引數引用,區別為,符號#可以進行與編譯,進行型別匹配,而$不進行資料型別匹配 例:select * from table where name = #name#,其中如果name為varchar型別,#n
第四章:activiti RuntimeService設定獲和取流程變數,及與taskService的區別,開始和完成任務時設定流程變數
上一章我們講了taskService獲取流程變數的過程,這裡我們講講RuntimeService是怎麼設定和獲取的,其實過程跟taskService是差不多的。RuntimeService 與流程例項及執行物件相關,對於的表是:act_ru_executionTaskServ