转载:

简介

针对文本相似判定,本文提供余弦相似度和SimHash两种算法,并根据实际项目遇到的一些问题,给出相应的解决方法。经过实际测试表明:余弦相似度算法适合于短文本,而SimHash算法适合于长文本,并且能应用于大数据环境中。

余弦相似度

原理

余弦定理:

                  

图-1 余弦定理图示

性质:

余弦值的范围在[-1,1]之间,值越趋近于1,代表两个向量的方向越趋近于0°,他们的方向更加一致,相应的相似度也越高。需要指出的是,在文本相似度判定中,因为文本特征向量定义的特殊性,其余弦值范围为[0,1],即向量夹角越趋向于90°,则两向量越不相似。

向量空间模型

VSM(Vector Space Model)把对文本内容的处理简化为向量空间中的向量运算。

概念:

1)文档(D):泛指文档或文档片段,一般表征一篇文档。

2)词汇(T):文本内容特征的基本语言单位,包含字、词、词组或短语。

3)权重(W):表征词汇T的权重,在文档D中的重要程度。

权重:

目前表征一个字词在一个文本集或者语料库中某篇文本中的重要程度的统计方法为TF-IDF(term frequency–inverse document frequency),词汇的重要性随着它在文件中出现的次数成正比增加,但同时会随着它在语料库中出现的频率成反比下降,详细内容在此不赘述。但是本文在实际项目中面临的问题是,文本集是变动的,而且变化速率比较快,因此并不适用于采用TF-IDF方法。本文采用非常简单直观的方法,即以词频来表征该词汇在文本中的重要程度(即权重)。

向量对齐:

由于在实际应用中,表征文本特征的两个向量的长度是不同的,因此必然需要对上述向量进行处理。目前存在两种方法:1)剔除掉向量中不重要的词汇,从而使得两个向量长度保持一致,目前主要依靠经验设定一些关键词来处理,但是其准确率不可保证;2)归并向量,并根据原向量是否在新向量(归并后的向量)存在,若存在则以该词汇的词频来表征,若不存在则该节点置为0,示例如下:

Text1: 我/是/中国人/

Text2: 我们/是/中国人/

Vector: 我/是/中国人/我们/

Vector1 = (1, 1, 1, 0)

Vector2 = (0, 1, 1, 1)

上述“/”为采用IK分词,智能切分后的间隔符,则归并后的向量如Vector所示,对齐后的向量分别为Vector1 和Vector2。之后则根据两向量的余弦值确定相似度。

文本特例

由于在实际项目中,本文发现了2个特例,并相应给出了解决方案。

1)长句包含短句(无需完全包含):

Text1:“贯彻强军目标出实招用实劲 努力开创部队建设新局面”

Text2:“在接见驻浙部队领导干部时强调 贯彻强军目标出实招用实劲 努力开创部队建设新局面”

上述两个文本为网络上实际的网页标题,若简单以余弦相似度来判定,其误判率是比较高的。本文解决方案为:若长句长度(中文切分后以词汇为单位表征,并非以字符为单位)为短句的1.5倍,则针对长句选定短句长度的文本内容逐个与短句进行相似度判定,直至长句结束,若中间达到预设的阈值,则跳出该循环,否则判定文本不相似。

2)文本中存在同义表述

Text1:“台湾居民明日起持台胞证可通关 无需办理签注”

Text2:“明起台胞来京无需办理签注 电子台胞证年内实施”

上述两个文本中“台胞”和“台湾居民”,“明日起”和“明起”为同义表述,可以理解为近义词,但不完全为近义词范畴。本文解决方案为引入同义词词典,鉴于中文词汇的丰富性,其能在一定程度上缓解,仍然不是根本解决之法。

应用场景及优缺点

本文目前将该算法应用于网页标题合并和标题聚类中,目前仍在尝试应用于其它场景中。

优点:计算结果准确,适合对短文本进行处理。

缺点:需要逐个进行向量化,并进行余弦计算,比较消耗CPU处理时间,因此不适合长文本,如网页正文、文档等。

  余弦相似度算法源程序:

public class ElementDict {
private String term;
private int freq;

public ElementDict(String term, int freq) {
this.term = term;
this.freq = freq;
}

public void setFreq (int freq) {
this.freq = freq;
}

public String getTerm() {
return term;
}

public int getFreq() {
return freq;
}

}

Class Element

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.HashMap;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;

import org.apache.lucene.analysis.TokenStream;
import org.apache.lucene.analysis.tokenattributes.CharTermAttribute;
import org.wltea.analyzer.lucene.IKAnalyzer;

public class TextCosine {
private Map<String, String> map= null;

public TextCosine() {
map = new HashMap<String, String>();
try {
InputStreamReader isReader = new InputStreamReader(new FileInputStream(TextCosine.class.getResource("synonyms.dict").getPath()), "UTF-8");
BufferedReader br = new BufferedReader(isReader);
String s = null;
while ((s = br.readLine()) !=null) {
String []synonymsEnum = s.split("→");
map.put(synonymsEnum[0], synonymsEnum[1]);
}
br.close();
} catch (IOException e) {
e.printStackTrace();
}
}

public List<ElementDict> tokenizer(String str) {
List<ElementDict> list = new ArrayList<ElementDict>();
IKAnalyzer analyzer = new IKAnalyzer(true);
try {
TokenStream stream = analyzer.tokenStream("", str);
CharTermAttribute cta = stream.addAttribute(CharTermAttribute.class);
stream.reset();
int index = -1;
while (stream.incrementToken()) {
if ((index = isContain(cta.toString(), list)) >= 0) {
list.get(index).setFreq(list.get(index).getFreq() + 1);
}
else {
list.add(new ElementDict(cta.toString(), 1));
}
}
analyzer.close();
} catch (IOException e) {
e.printStackTrace();
}
return list;
}

public int isContain(String str, List<ElementDict> list) {
for (ElementDict ed : list) {
if (ed.getTerm().equals(str)) {
return list.indexOf(ed);
} else if (map.get(ed.getTerm())!= null && map.get(ed.getTerm()).equals(str)) {
return list.indexOf(ed);
}
}
return -1;
}

public List<String> mergeTerms(List<ElementDict> list1, List<ElementDict> list2) {
List<String> list = new ArrayList<String>();
for (ElementDict ed : list1) {
if (!list.contains(ed.getTerm())) {
list.add(ed.getTerm());
} else if (!list.contains(map.get(ed.getTerm()))) {
list.add(ed.getTerm());
}
}

for (ElementDict ed : list2) {
if (!list.contains(ed.getTerm())) {
list.add(ed.getTerm());
} else if (!list.contains(map.get(ed.getTerm()))) {
list.add(ed.getTerm());
}
}
return list;
}

public int anslysisTerms(List<ElementDict> list1, List<ElementDict> list2) {
int len1 = list1.size();
int len2 = list2.size();
if (len2 >= len1 * 1.5) {
List<ElementDict> newList = new ArrayList<ElementDict>();
for (int i = 0; i + len1 <= len2; i++) {
for (int j = 0; j < len1; j++)
newList.add(list2.get(i+j));

newList = adjustList(newList, list2, len2, len1, i);
if (getResult(analysis(list1, newList)))
return 1;
else
newList.clear();
}
} else if (len1 >= len2 * 1.5) {
List<ElementDict> newList = new ArrayList<ElementDict>();
for (int i = 0; i + len2 <= len1; i++) {
for (int j = 0; j < len2; j++)
newList.add(list1.get(i+j));

newList = adjustList(newList, list1, len1, len2, i);
if (getResult(analysis(newList, list2)))
return 1;
else
newList.clear();
}
} else {
if (getEasyResult(analysis(list1, list2)))
return 1;
}
return 0;
}

public List<ElementDict> adjustList(List<ElementDict> newList, List<ElementDict> list, int lenBig, int lenSmall, int index) {
int gap = lenBig -lenSmall;
int size = (gap/2 > 2) ? 2: gap/2;
if (index < gap/2) {
for (int i = 0; i < size; i++) {
newList.add(list.get(lenSmall+index+i));
}
} else {
for (int i = 0; i > size; i++) {
newList.add(list.get(lenBig-index-i));
}
}
return newList;
}

public double analysis(List<ElementDict> list1, List<ElementDict> list2) {
List<String> list = mergeTerms(list1, list2);
List<Integer> weightList1 = assignWeight(list, list1);
List<Integer> weightList2 = assignWeight(list, list2);
return countCosSimilariry(weightList1, weightList2);
}

public List<Integer> assignWeight(List<String> list, List<ElementDict> list1) {
List<Integer> vecList = new ArrayList<Integer>(list.size());
boolean isEqual = false;
for (String str : list) {
for (ElementDict ed : list1) {
if (ed.getTerm().equals(str)) {
isEqual = true;
vecList.add(new Integer(ed.getFreq()));
} else if (map.get(ed.getTerm())!= null && map.get(ed.getTerm()).equals(str)) {
isEqual = true;
vecList.add(new Integer(ed.getFreq()));
}
}

if (!isEqual) {
vecList.add(new Integer(0));
}
isEqual = false;
}
return vecList;
}

public double countCosSimilariry(List<Integer> list1, List<Integer> list2) {
double countScores = 0;
int element = 0;
int denominator1 = 0;
int denominator2 = 0;
int index = -1;
for (Integer it : list1) {
index ++;
int left = it.intValue();
int right = list2.get(index).intValue();
element += left * right;
denominator1 += left * left;
denominator2 += right * right;
}
try {
countScores = (double)element / Math.sqrt(denominator1 * denominator2);
} catch (ArithmeticException e) {
e.printStackTrace();
}
return countScores;
}

public boolean getResult(double scores) {
System.out.println(scores);
if (scores >= 0.85)
return true;
else
return false;
}

public boolean getEasyResult(double scores) {
System.out.println(scores);
if (scores >= 0.75)
return true;
else
return false;
}

}

Class TextCosine

  备注:同义词词典“synonyms.dict”文件较大,完全可以自己构建,在此就不赘述了。

SimHash

SimHash为Google处理海量网页的采用的文本相似判定方法。该方法的主要目的是降维,即将高维的特征向量映射成f-bit的指纹,通过比较两篇文档指纹的汉明距离来表征文档重复或相似性。

过程

该算法设计十分精巧,主要过程如下:

1.  文档特征量化为向量;

2.  计算特征词汇哈希值,并辅以权重进行量化;

3.  针对f-bit指纹,按位进行叠加运算;

4.  针对叠加后的指纹,若对应位为正,则标记为1,否则标记为0。

  备注:此处f-bit指纹,可以根据应用需求,定制为16位、32位、64位或者其它位数等。

如图-2所示,为SimHash作者Charikar在论文中的图示,本文结合实际项目解释如下:Doc表征一篇文本,feature为该文本经过中文分词后的词汇组合,按列向量组织,weight为对应词汇在文本中的词频,之后经过某种哈希计算得出哈希值,见图中1和0的组合,剩余部分不再赘述。需要指出,Charikar在论文中并未指定需要采用哪种哈希函数,本文作者认为,只要哈希计算值能够均衡化、分散化,哈希函数可以根据实际应用场景进行设计,本文在实际的项目中自行设计哈希函数,虽未经过完全验证,但是测试结果表明,该函数当前能够满足需求。

图-2 SimHash处理过程

汉明距离

汉明距离应用于数据传输差错控制编码,它表示两个(相同长度)字对应位不同的数量。鉴于SimHash最后计算出的指纹采用0和1进行组织,故而用其来衡量文档相似性或者重复性,该部分详细内容在此不再赘述。

应用场景与优缺点

本文目前将该算法应用于话题发现和内容聚合等场景中,同时也在尝试其它应用场景。

优点:文本处理速率快,计算后的指纹能够存储于数据库,因此对海量文本相似判定非常适合。

缺点:由于短文本的用于哈希计算的数据源较少,因此短文本相似度识别率低。

  SimHash算法源程序:

public class TermDict {
private String term;
private int freq;

public TermDict(String term, int freq)
{
this.term = term;
this.freq = freq;
}

public String getTerm() {
return term;
}

public void setTerm(String term) {
this.term = term;
}

public int getFreq() {
return freq;
}

public void setFreq(int freq) {
this.freq = freq;
}

}

Class TermDict

 1 public class TermDict {2     private String term;3     private int freq;4     5     public TermDict(String term, int freq) 6     {7         this.term = term;8         this.freq = freq;9     }
10
11     public String getTerm() {
12         return term;
13     }
14
15     public void setTerm(String term) {
16         this.term = term;
17     }
18
19     public int getFreq() {
20         return freq;
21     }
22
23     public void setFreq(int freq) {
24         this.freq = freq;
25     }
26
27 }

import java.io.IOException;
import java.math.BigInteger;
import java.util.List;
import java.util.ArrayList;

import org.wltea.analyzer.lucene.IKAnalyzer;
import org.apache.lucene.analysis.TokenStream;
import org.apache.lucene.analysis.tokenattributes.CharTermAttribute;

public class SimHash {
private String tokens;
private int hashBits = 64;
private int distance = 5;

public SimHash(String tokens)
{
this.tokens = tokens;
}

public SimHash(String tokens, int hashBits, int distance)
{
this.tokens = tokens;
this.hashBits = hashBits;
this.distance = distance;
}

public List<TermDict> tokenizer()
{
List<TermDict> terms = new ArrayList<TermDict>();
IKAnalyzer analyzer = new IKAnalyzer(true);
try {
TokenStream stream = analyzer.tokenStream("", this.tokens);
CharTermAttribute cta = stream.addAttribute(CharTermAttribute.class);
stream.reset();
int index = -1;
while (stream.incrementToken())
{
if ((index = isContain(cta.toString(), terms)) >= 0)
{
terms.get(index).setFreq(terms.get(index).getFreq()+1);
}
else
{
terms.add(new TermDict(cta.toString(), 1));
}
}
analyzer.close();
} catch (IOException e) {
e.printStackTrace();
}
return terms;
}

public int isContain(String str, List<TermDict> terms)
{
for (TermDict td : terms)
{
if (str.equals(td.getTerm()))
{
return terms.indexOf(td);
}
}
return -1;
}

public BigInteger simHash(List<TermDict> terms)
{
int []v = new int[hashBits];
for (TermDict td : terms)
{
String str = td.getTerm();
int weight = td.getFreq();
BigInteger bt = shiftHash(str);
for (int i = 0; i < hashBits; i++)
{
BigInteger bitmask = new BigInteger("1").shiftLeft(i);
if ( bt.and(bitmask).signum() != 0)
{
v[i] += weight;
}
else
{
v[i] -= weight;
}
}
}

BigInteger fingerPrint = new BigInteger("0");
for (int i = 0; i < hashBits; i++)
{
if (v[i] >= 0)
{
fingerPrint = fingerPrint.add(new BigInteger("1").shiftLeft(i)); // update the correct fingerPrint
}
}
return fingerPrint;
}

public BigInteger shiftHash(String str)
{
if (str == null || str.length() == 0)
{
return new BigInteger("0");
}
else
{
char[] sourceArray = str.toCharArray();
BigInteger x = BigInteger.valueOf((long) sourceArray[0] << 7);
BigInteger m = new BigInteger("131313");
for (char item : sourceArray)
{
x = x.multiply(m).add(BigInteger.valueOf((long)item));
}
BigInteger mask = new BigInteger("2").pow(hashBits).subtract(new BigInteger("1"));
boolean flag = true;
for (char item : sourceArray)
{
if (flag)
{
BigInteger tmp = BigInteger.valueOf((long)item << 3);
x = x.multiply(m).xor(tmp).and(mask);
}
else
{
BigInteger tmp = BigInteger.valueOf((long)item >> 3);
x = x.multiply(m).xor(tmp).and(mask);
}
flag = !flag;
}

if (x.equals(new BigInteger("-1")))
{
x = new BigInteger("-2");
}
return x;
}
}

public BigInteger getSimHash()
{
return simHash(tokenizer());
}

public int getHammingDistance(SimHash hashData)
{
BigInteger m = new BigInteger("1").shiftLeft(hashBits).subtract(new BigInteger("1"));
System.out.println(getFingerPrint(getSimHash().toString(2)));
System.out.println(getFingerPrint(hashData.getSimHash().toString(2)));
BigInteger x = getSimHash().xor(hashData.getSimHash()).and(m);
int tot = 0;
while (x.signum() != 0)
{
tot += 1;
x = x.and(x.subtract(new BigInteger("1")));
}
System.out.println(tot);
return tot;
}

public String getFingerPrint(String str)
{
int len = str.length();
for (int i = 0; i < hashBits; i++)
{
if (i >= len)
{
str = "0" + str;
}
}
return str;
}

public void getResult(SimHash hashData)
{
if (getHammingDistance(hashData) <= distance)
{
System.out.println("match");
}
else
{
System.out.println("false");
}
}

}

Class SimHash

  1 import java.io.IOException;2 import java.math.BigInteger;3 import java.util.List;4 import java.util.ArrayList;5 6 import org.wltea.analyzer.lucene.IKAnalyzer;7 import org.apache.lucene.analysis.TokenStream;8 import org.apache.lucene.analysis.tokenattributes.CharTermAttribute;9 10 public class SimHash {11     private String tokens;12     private int hashBits = 64;13     private int distance = 5;14     15     public SimHash(String tokens)16     {17         this.tokens = tokens;18     }19     20     21     public SimHash(String tokens, int hashBits, int distance)22     {23         this.tokens = tokens;24         this.hashBits = hashBits;25         this.distance = distance;26     }27     28     29     public List<TermDict> tokenizer()30     {31         List<TermDict> terms = new ArrayList<TermDict>();32         IKAnalyzer analyzer = new IKAnalyzer(true);33         try {34             TokenStream stream = analyzer.tokenStream("", this.tokens);35             CharTermAttribute cta = stream.addAttribute(CharTermAttribute.class);36             stream.reset();37             int index = -1;38             while (stream.incrementToken()) 39             {40                 if ((index = isContain(cta.toString(), terms)) >= 0)41                 {42                     terms.get(index).setFreq(terms.get(index).getFreq()+1);43                 }44                 else 45                 {46                     terms.add(new TermDict(cta.toString(), 1));47                 }48             }49             analyzer.close();50         } catch (IOException e) {51             e.printStackTrace();52         }53         return terms;54     }55     56     57     public int isContain(String str, List<TermDict> terms)58     {59         for (TermDict td : terms)60         {61             if (str.equals(td.getTerm()))62             {63                 return terms.indexOf(td);64             }65         }66         return -1;67     }68     69     70     public BigInteger simHash(List<TermDict> terms)71     {72         int []v = new int[hashBits];73         for (TermDict td : terms)74         {75             String str = td.getTerm();76             int weight = td.getFreq();77             BigInteger bt = shiftHash(str);78             for (int i = 0; i < hashBits; i++)79             {80                 BigInteger bitmask = new BigInteger("1").shiftLeft(i);81                 if ( bt.and(bitmask).signum() != 0)82                 {83                     v[i] += weight;84                 }85                 else86                 {87                     v[i] -= weight;88                 }89             }90         }91         92         BigInteger fingerPrint = new BigInteger("0");93         for (int i = 0; i < hashBits; i++)94         {95             if (v[i] >= 0)96             {97                 fingerPrint = fingerPrint.add(new BigInteger("1").shiftLeft(i));   // update the correct fingerPrint98             }99         }
100         return fingerPrint;
101     }
102
103
104     public BigInteger shiftHash(String str)
105     {
106         if (str == null || str.length() == 0)
107         {
108             return new BigInteger("0");
109         }
110         else
111         {
112             char[] sourceArray = str.toCharArray();
113             BigInteger x = BigInteger.valueOf((long) sourceArray[0] << 7);
114             BigInteger m = new BigInteger("131313");
115             for (char item : sourceArray)
116             {
117                 x = x.multiply(m).add(BigInteger.valueOf((long)item));
118             }
119             BigInteger mask = new BigInteger("2").pow(hashBits).subtract(new BigInteger("1"));
120             boolean flag = true;
121             for (char item : sourceArray)
122             {
123                 if (flag)
124                 {
125                     BigInteger tmp = BigInteger.valueOf((long)item << 3);
126                     x = x.multiply(m).xor(tmp).and(mask);
127                 }
128                 else
129                 {
130                     BigInteger tmp = BigInteger.valueOf((long)item >> 3);
131                     x = x.multiply(m).xor(tmp).and(mask);
132                 }
133                 flag = !flag;
134             }
135
136             if (x.equals(new BigInteger("-1")))
137             {
138                 x = new BigInteger("-2");
139             }
140             return x;
141         }
142     }
143
144
145     public BigInteger getSimHash()
146     {
147         return simHash(tokenizer());
148     }
149
150
151     public int getHammingDistance(SimHash hashData)
152     {
153         BigInteger m = new BigInteger("1").shiftLeft(hashBits).subtract(new BigInteger("1"));
154         System.out.println(getFingerPrint(getSimHash().toString(2)));
155         System.out.println(getFingerPrint(hashData.getSimHash().toString(2)));
156         BigInteger x = getSimHash().xor(hashData.getSimHash()).and(m);
157         int tot = 0;
158         while (x.signum() != 0)
159         {
160             tot += 1;
161             x = x.and(x.subtract(new BigInteger("1")));
162         }
163         System.out.println(tot);
164         return tot;
165     }
166
167
168     public String getFingerPrint(String str)
169     {
170         int len = str.length();
171         for (int i = 0; i < hashBits; i++)
172         {
173             if (i >= len)
174             {
175                 str = "0" + str;
176             }
177         }
178         return str;
179     }
180
181
182     public void getResult(SimHash hashData)
183     {
184         if (getHammingDistance(hashData) <= distance)
185         {
186             System.out.println("match");
187         }
188         else
189         {
190             System.out.println("false");
191         }
192     }
193
194 }

  备注:源程序中“131313”只是作者挑选的一个较大的素数而已,不代表特别含义,该数字可以根据需求进行设定。


  作者:志青云集
  出处:http://www.cnblogs.com/lyssym/p/4880896.html
  

转载于:https://www.cnblogs.com/nucdy/p/9059880.html

文本挖掘之 文本相似度判定相关推荐

  1. 文本挖掘之文本相似度判定

    刘 勇   Email:lyssym@sina.com 简介 针对文本相似判定,本文提供余弦相似度和SimHash两种算法,并根据实际项目遇到的一些问题,给出相应的解决方法.经过实际测试表明:余弦相似 ...

  2. pbewithmd5anddes算法 对应.net_文本相似度算法之-simhash

    文本相似度算法种类繁多,今天先介绍一种常见的网页去重算法Simhash. 1.什么是simhash simhash是google于2007年发布的一篇论文<Detecting Near-dupl ...

  3. 从0到1,了解NLP中的文本相似度

    本文由云+社区发表 作者:netkiddy 导语 AI在2018年应该是互联网界最火的名词,没有之一.时间来到了9102年,也是项目相关,涉及到了一些AI写作相关的功能,为客户生成一些素材文章.但是, ...

  4. 从0到1,了解NLP中的文本相似度 1

    导语 AI在2018年应该是互联网界最火的名词,没有之一.时间来到了9102年,也是项目相关,涉及到了一些AI写作相关的功能,为客户生成一些素材文章.但是,AI并不一定最懂你,客户对于AI写出来的文章 ...

  5. Jaccard文本相似度计算 Java程序

    本文作者:合肥工业大学 管理学院 钱洋 email:1563178220@qq.com 内容可能有不到之处,欢迎交流. Jaccard相似系数 两个集合A和B交集元素的个数在A.B并集中所占的比例,称 ...

  6. 文本相似度计算——Simhash算法(python实现)

    互联网网页存在着大量重复内容,必须有一套高效的去重算法,否则爬虫将做非常多的无用功,工作时效性无法得到保证,更重要的是用户体验也不好.业界关于文本指纹去重的算法众多,如 k-shingle 算法.go ...

  7. NLP文本相似度(TF-IDF)

    前言 我们在比较事物时,往往会用到"不同","一样","相似"等词语,这些词语背后都涉及到一个动作--双方的比较.只有通过比较才能得出结论, ...

  8. python汉明距离_simhash+汉明距离计算文本相似度

    ****由于最近需要做大规模的文本相似度的计算,所以用到了simhash+汉明距离来快速计算文本的相似度.** **simhash的原理如下图:其中的weight采用的是jieba的tf-idf的结果 ...

  9. 基于隐马尔科夫模型文本相似度问题研究

    文本相似度是表示两个或者多个文本之间匹配程度的一个度量参数,相似度数值大,说明文本相似度高:反之文件相似程度就低.文本相似度的精确计算问题是进行信息处理的关键. 在如今信息技术飞速发展的互联网时代,文 ...

最新文章

  1. string数组怎么定义
  2. Oracle数据库用户角色、表空间创建、删除命令
  3. 算法与数据结构(约瑟夫问题)
  4. 03-instancing 工程分析详解
  5. python做自动化如何定位动态元素_python-web自动化-元素定位
  6. EF中使用SQL语句或存储过程
  7. 图片与路径(Path)的应用
  8. 微软Office Live Workspace测试版开放全球注册
  9. 跳转微信公众号首页方式
  10. 在 100% 鲜活的时间,请让我遇见你
  11. wing ftp linux 怎么用,Wing FTP Server使用方法(操作步骤)
  12. 盘点软件可以解决哪些固定资产盘点问题
  13. 不明觉厉!用了近10年,才有人读懂这篇论文
  14. k8s部署(多节点)
  15. 莫队算法二(树上莫队cot2,Haruna’s Breakfast)
  16. 阿里云 mysql 1045_解决阿里云登录mysql出现的1045错误
  17. 红海or蓝海?数据分析告诉你:在线教育的井喷与未来
  18. CentOs中安装并运行rocketmq(报错 ignoring input and appending output to ‘nohup.out’;jps: command not found)
  19. win 7文件夹怎么设置密码
  20. 感动中国,感动你我她

热门文章

  1. 多线程,并发,异步,死锁
  2. 重操JS旧业第五弹:函数
  3. uni-app 图片适配 动态计算图片高度
  4. Springboot03整合SpringDataJPA访问MySQL数据库
  5. my footprint :走过的路
  6. 什么是线程死锁?如何解决?(蚂蚁金服面试题)
  7. HTML: 引号不能忽视
  8. Python爬虫从入门到放弃(十三)之 Scrapy框架的命令行详解
  9. 关于fragment中使用onActivityResult
  10. (转)Django ==== 实战学习篇九 在session中保存购物车