forked from wshenyi/wshenyi.github.io
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcontent.json
More file actions
1 lines (1 loc) · 228 KB
/
content.json
File metadata and controls
1 lines (1 loc) · 228 KB
1
{"meta":{"title":"Godway's Notebook","subtitle":"wsy","description":"","author":"Godway","url":"https://godway999.github.io","root":"/"},"pages":[{"title":"","date":"2020-02-18T13:14:01.971Z","updated":"2019-05-04T05:18:09.000Z","comments":true,"path":"google16734bd3d7a7f6df.html","permalink":"https://godway999.github.io/google16734bd3d7a7f6df.html","excerpt":"","text":"google-site-verification: google16734bd3d7a7f6df.html"},{"title":"about","date":"2019-04-12T16:00:43.000Z","updated":"2019-06-18T11:53:10.622Z","comments":true,"path":"about/index.html","permalink":"https://godway999.github.io/about/index.html","excerpt":"","text":"Hello Welcome to my studio!"},{"title":"tags","date":"2019-05-03T13:44:33.000Z","updated":"2019-05-03T15:27:54.822Z","comments":true,"path":"tags/index.html","permalink":"https://godway999.github.io/tags/index.html","excerpt":"","text":""},{"title":"Categories","date":"2019-05-03T13:47:27.000Z","updated":"2019-05-03T14:05:15.097Z","comments":true,"path":"categories/index.html","permalink":"https://godway999.github.io/categories/index.html","excerpt":"","text":""}],"posts":[{"title":"Introduction to Visualization","slug":"Others7","date":"2020-03-07T17:38:23.000Z","updated":"2020-03-07T17:56:45.742Z","comments":true,"path":"2020/03/08/Others7/","link":"","permalink":"https://godway999.github.io/2020/03/08/Others7/","excerpt":"","text":"1234567import pandas as pdimport matplotlib.pyplot as pltimport seaborn as snsimport numpy as np%matplotlib inlinepd.plotting.register_matplotlib_converters()print(\"Setup Complete\") Setup Complete 1data = pd.read_csv('vtest.csv', index_col=0) 1data.head() .dataframe tbody tr th:only-of-type { vertical-align: middle; } .dataframe tbody tr th { vertical-align: top; } .dataframe thead th { text-align: right; } pp1 pp2 pp3 pp4 pp5 pp6 0 -94 70 -53 38 -66 -56 1 -75 18 -38 88 35 -5 2 -21 -91 14 46 43 22 3 -22 65 3 -15 57 20 4 95 -42 -18 67 81 60 1data.shape (12, 6) Line Chart 12345678# Set the width and height of the figureplt.figure(figsize=(10, 6))# Add titileplt.title(\"Line Chart\")# Plot line chartsns.lineplot(data=data) 123456# if you not explictly designate the label parameter, it will use column's title as defaultplt.figure(figsize=(10, 6))sns.lineplot(data=data.pp1, label=\"pp1\")sns.lineplot(data=data.pp2, label=\"pp2\")plt.xlabel(\"Month\") Bar Chart 1234567891011# Set the width and height of the figureplt.figure(figsize=(10,6))# Add titleplt.title(\"Bar Chart\")# Plot Bar chartsns.barplot(x=data.index, y=data.pp3)# Add label for vertical axisplt.xlabel(\"Month\") Heatmap 1234567891011# Set the width and height of the figureplt.figure(figsize=(10, 6))# Add titleplt.title(\"Heatmap\")# Plot heatmapsns.heatmap(data=data, annot=True)# Add label for horizontal axisplt.ylabel(\"Month\") Scatter Plots Normal scatter chart Use scatter plots to display the relationships between two data 1234plt.figure(figsize=(10, 6))sns.scatterplot(x=data.pp3, y=data.pp4)plt.xlabel(\"pp3-value-range\")plt.ylabel(\"pp4-value-range\") Color-coded scatter plots We can use scatter plots to display the relationships between (not two, but...) three variables! One way of doing this is by color-coding the points. 12plt.figure(figsize=(10, 6))sns.scatterplot(x=data.pp3, y=data.pp4, hue=np.random.randint(0, 2, size=data.shape[0])) Regression line Plot the line that best fits the data 1234plt.figure(figsize=(10, 6))sns.regplot(x=data.index, y=data.pp3)sns.regplot(x=data.index, y=data.pp4)plt.xlabel(\"Month\") Compare two regression line we can use the sns.lmplot command to add two regression lines, comparing two lines' relation strength 123plt.figure(figsize=(10, 6))data['YN'] = np.random.randint(0, 2, size=data.shape[0])sns.lmplot(x='pp3', y='pp4', hue='YN', data=data) Categorical scatter plot We can adapt the design of the scatter plot to feature a categorical variable (like labels) on one of the main axes. We'll refer to this plot type as a categorical scatter plot, and we build it with the sns.swarmplot command. 1234plt.figure(figsize=(10, 6))category = np.random.randint(0, 3, size=1000)value = np.random.randint(0, 100, size=1000)sns.swarmplot(x=category, y=value) Distributions Histograms 123plt.figure(figsize=(10, 6))value = np.random.randint(0, 10, size=100)sns.distplot(a=value, kde=False) kde=False is something we'll always provide when creating a histogram, as leaving it out will create a slightly different plot. Withkde=True, kernel density estimate (KDE) curve would generate at the same time 12plt.figure(figsize=(10, 6))sns.distplot(a=value, kde=True) Density plots The next type of plot is a kernel density estimate (KDE) plot. In case you're not familiar with KDE plots, you can think of it as a smoothed histogram. Setting shade=True colors the area below the curve 12plt.figure(figsize=(10, 6))sns.kdeplot(data=value, shade=True) 2D KDE plots 1234plt.figure(figsize=(10, 6))x_value = np.random.randint(0, 10, size=100)y_value = np.random.randint(10, 20, size=100)sns.jointplot(x=x_value, y=y_value, kind=\"kde\") Color-coded plots We create a different histogram for each species by using the sns.distplot command three times. We use label= to set how each histogram will appear in the legend. 12345plt.figure(figsize=(10, 6))sns.distplot(a=np.random.randint(0, 10, size=50), label=\"data1\", kde=False)sns.distplot(a=np.random.randint(5, 15, size=50), label=\"data2\", kde=False)sns.distplot(a=np.random.randint(15, 25, size=50), label=\"data3\", kde=False)plt.legend() 12345plt.figure(figsize=(10, 6))sns.kdeplot(data=np.random.randint(0, 10, size=50), label=\"data1\", shade=True)sns.kdeplot(data=np.random.randint(5, 15, size=50), label=\"data2\", shade=True)sns.kdeplot(data=np.random.randint(15, 25, size=50), label=\"data3\", shade=True)plt.legend() Changing styles with seaborn Seaborn has five different themes: (1)\"darkgrid\", (2)\"whitegrid\", (3)\"dark\", (4)\"white\", and (5)\"ticks\" 123456style = [\"darkgrid\", \"whitegrid\", \"dark\", \"white\", \"ticks\"]plt.figure(figsize=(30, 5))for i in range(i): plt.subplot(1, 5, i + 1) sns.set_style(style[i]) sns.lineplot(data=np.random.randint(10, size=20))","categories":[{"name":"Data Science","slug":"Data-Science","permalink":"https://godway999.github.io/categories/Data-Science/"}],"tags":[]},{"title":"Introductions to Pandas","slug":"Others6","date":"2020-03-05T10:09:23.000Z","updated":"2020-03-07T02:12:46.193Z","comments":true,"path":"2020/03/05/Others6/","link":"","permalink":"https://godway999.github.io/2020/03/05/Others6/","excerpt":"","text":"1import pandas as pd DataFrame 1pd.DataFrame({'Yes': [50, 21], 'No': [131, 2]}) .dataframe tbody tr th:only-of-type { vertical-align: middle; } .dataframe tbody tr th { vertical-align: top; } .dataframe thead th { text-align: right; } Yes No 0 50 131 1 21 2 DataFrame is actually a dictionary whose keys are the column names (String), and whose values are a list of entries(List) 123pd.DataFrame({'Bob': ['I liked it.', 'It was awful.'], 'Sue': ['Pretty good.', 'Bland.']}, index=['Product A', 'Product B']) .dataframe tbody tr th:only-of-type { vertical-align: middle; } .dataframe tbody tr th { vertical-align: top; } .dataframe thead th { text-align: right; } Bob Sue Product A I liked it. Pretty good. Product B It was awful. Bland. Sometimes we can manually assign index of row instead of defaut index which starts from 0 Series A Series, by contrast, is a sequence of data values. If a DataFrame is a table, a Series is a list. And in fact you can create one with nothing more than a list: 1pd.Series([1, 2, 3, 4, 5]) 0 1 1 2 2 3 3 4 4 5 dtype: int64 A Series is, in essence, a single column of a DataFrame. So you can assign column values to the Series the same way as before, using an index parameter. However, a Series does not have a column name, it only has one overall name: 12pd.Series([30, 35, 40], index=['2015 Sales', '2016 Sales', '2017 Sales'], name='Product A') 2015 Sales 30 2016 Sales 35 2017 Sales 40 Name: Product A, dtype: int64 Reading data files 1data = pd.read_csv(\"test.csv\") Use function pd.read_csv() to load a csv file. We can use the shape attribute to check how large the resulting DataFrame is: 1data.shape (6, 4) We can examine the contents of the resultant DataFrame using the head() command, which grabs the first five rows: 1data.head() .dataframe tbody tr th:only-of-type { vertical-align: middle; } .dataframe tbody tr th { vertical-align: top; } .dataframe thead th { text-align: right; } Unnamed: 0 col1 col2 col3 0 0 1 2 a 1 1 1 2 b 2 2 2 4 c 3 3 3 6 a 4 4 5 10 b The pd.read_csv() function is well-endowed, with over 30 optional parameters you can specify. For example, you can see in this dataset that the CSV file has a built-in index, which pandas did not pick up on automatically. To make pandas use that column for the index (instead of creating a new one from scratch), we can specify an index_col. 12data = pd.read_csv(\"test.csv\", index_col=0)data.head() .dataframe tbody tr th:only-of-type { vertical-align: middle; } .dataframe tbody tr th { vertical-align: top; } .dataframe thead th { text-align: right; } col1 col2 col3 0 1 2 a 1 1 2 b 2 2 4 c 3 3 6 a 4 5 10 b Naive accessors DataFrame in pandas is very similar to a dictionary. You can access it by using key-value format or calling title built in DataFrame 123c1 = data['col1'] # key-value c2 = data.col1 # dic.column_nameprint(c1 == c2) 0 True 1 True 2 True 3 True 4 True 5 True Name: col1, dtype: bool Because of the value,or the column, in DataFrame is organized in List, we can access row value using index operator [] 1data.col1[3] 3 Indexing in pandas pandas has its own accessor operators, loc and iloc. The second paramter distinct them: index for iloc and string for 'loc'. iloc is conceptually simpler than loc because it ignores the dataset's indices. When we use iloc we treat the dataset like a big matrix. loc, by contrast, uses the information in the indices to do its work. When we use loc we want to make our code more meaningful and humanable (easier to read) Index-based selection selecting data based on its numerical position in the data 1data.iloc[3, 0] # second parameter is a numerical index 3 Label-based selection selecting data based on its row index and column name 1data.loc[3, 'col1'] # second parameter is a list of column names in string 3 Conditional selection Select specified value using condition operation and its return is a matrix of bool value. 1data.col1 == 3 0 False 1 False 2 False 3 True 4 False 5 False Name: col1, dtype: bool By converging conditional selection, we can use some colums' value to locate other rows or columns. You can also include the set operation: &and | 1data.loc[data.col1 == 3] .dataframe tbody tr th:only-of-type { vertical-align: middle; } .dataframe tbody tr th { vertical-align: top; } .dataframe thead th { text-align: right; } col1 col2 col3 3 3 6 a pandas has some built-in conditional selectors, two of which we will highlight here. isin() The first is isin. isin is lets you select data whose value \"is in\" a list of values. For example, you can use it to select rows whose value are 2 or 5 in col1. 1data.loc[data.col1.isin([2, 5])] .dataframe tbody tr th:only-of-type { vertical-align: middle; } .dataframe tbody tr th { vertical-align: top; } .dataframe thead th { text-align: right; } col1 col2 col3 2 2 4 c 4 5 10 b isnull() & notnull() The second is isnull (and its companion notnull). These methods let you highlight values which are (or are not) empty (NaN). 1data.loc[data.col1.isnull()] .dataframe tbody tr th:only-of-type { vertical-align: middle; } .dataframe tbody tr th { vertical-align: top; } .dataframe thead th { text-align: right; } col1 col2 col3 1data.loc[data.col1.notnull()] .dataframe tbody tr th:only-of-type { vertical-align: middle; } .dataframe tbody tr th { vertical-align: top; } .dataframe thead th { text-align: right; } col1 col2 col3 0 1 2 a 1 1 2 b 2 2 4 c 3 3 6 a 4 5 10 b 5 8 16 c Summary functions pandas provides some useful fuctions that can help us get some statistic information 1data.col1.describe() # for numerical values count 6.000000 mean 3.333333 std 2.732520 min 1.000000 25% 1.250000 50% 2.500000 75% 4.500000 max 8.000000 Name: col1, dtype: float64 list statistic information of that row 1data.col1.mean() 3.3333333333333335 access single attribute 1data.col3.describe() # for string values count 6 unique 3 top c freq 2 Name: col3, dtype: object list statistic information of string frequence. top means the string with the max frequence 12print(data.col1.unique())print(data.col3.unique()) [1 2 3 5 8] ['a' 'b' 'c'] 1data.col3.value_counts() c 2 a 2 b 2 Name: col3, dtype: int64 Maps it just as map function in python 1data.col2.map(lambda p: p / 2) 0 1.0 1 1.0 2 2.0 3 3.0 4 5.0 5 8.0 Name: col2, dtype: float64 Note: this operation does not change the original data. apply function is equivalent to map function, although they operate value sightly different. this function may change the original data!!! 123456def fun1(data): data.col2 = data.col2 - 2 * data.col1 return data # must return the modified datadata.apply(fun1, axis='columns') .dataframe tbody tr th:only-of-type { vertical-align: middle; } .dataframe tbody tr th { vertical-align: top; } .dataframe thead th { text-align: right; } col1 col2 col3 0 1 0 a 1 1 0 b 2 2 0 c 3 3 0 a 4 5 0 b 5 8 0 c 123456def fun2(data): data.iloc[1] = data.iloc[5] return data # must return the modified datadata.apply(fun2, axis='rows') /usr/local/lib/python3.7/site-packages/pandas/core/indexing.py:670: SettingWithCopyWarning: A value is trying to be set on a copy of a slice from a DataFrame See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy self._setitem_with_indexer(indexer, value) .dataframe tbody tr th:only-of-type { vertical-align: middle; } .dataframe tbody tr th { vertical-align: top; } .dataframe thead th { text-align: right; } col1 col2 col3 0 1 2 a 1 8 16 c 2 2 4 c 3 3 6 a 4 5 10 b 5 8 16 c This function apply is used for the situation when you do some complex data transforamtions. Any it also does not change the original data. Groupwise analysis groupby() function groups the same value from a given column into the same group. For instance, col3' only has 3 distinct characters: a,b,c. It generates 3 groups (3 rows): data.groupby('col3').col1/col2/col3. We can manipulate these groups seperately. More specify, data.groupby('col3') is a new DataFrame and we operate data in each group seperately. 123print(data.groupby('col3').col1.describe())print(data.groupby('col3').col2.describe())print(data.groupby('col3').col3.describe()) count mean std min 25% 50% 75% max col3 a 2.0 2.0 1.414214 1.0 1.5 2.0 2.5 3.0 b 1.0 5.0 NaN 5.0 5.0 5.0 5.0 5.0 c 3.0 6.0 3.464102 2.0 5.0 8.0 8.0 8.0 count mean std min 25% 50% 75% max col3 a 2.0 4.0 2.828427 2.0 3.0 4.0 5.0 6.0 b 1.0 10.0 NaN 10.0 10.0 10.0 10.0 10.0 c 3.0 12.0 6.928203 4.0 10.0 16.0 16.0 16.0 count unique top freq col3 a 2 1 a 2 b 1 1 b 1 c 3 1 c 3 1data.groupby(['col3', 'col1']).col2.describe() .dataframe tbody tr th:only-of-type { vertical-align: middle; } .dataframe tbody tr th { vertical-align: top; } .dataframe thead th { text-align: right; } count mean std min 25% 50% 75% max col3 col1 a 1 1.0 2.0 NaN 2.0 2.0 2.0 2.0 2.0 3 1.0 6.0 NaN 6.0 6.0 6.0 6.0 6.0 b 5 1.0 10.0 NaN 10.0 10.0 10.0 10.0 10.0 c 2 1.0 4.0 NaN 4.0 4.0 4.0 4.0 4.0 8 2.0 16.0 0.0 16.0 16.0 16.0 16.0 16.0 groupby() function can group multiple columns. And the index here is called multi-index. We can call reset_index() to restore it back to a normal index. 12dt = data.groupby(['col3', 'col1']).col2.describe()dt.reset_index() .dataframe tbody tr th:only-of-type { vertical-align: middle; } .dataframe tbody tr th { vertical-align: top; } .dataframe thead th { text-align: right; } col3 col1 count mean std min 25% 50% 75% max 0 a 1 1.0 2.0 NaN 2.0 2.0 2.0 2.0 2.0 1 a 3 1.0 6.0 NaN 6.0 6.0 6.0 6.0 6.0 2 b 5 1.0 10.0 NaN 10.0 10.0 10.0 10.0 10.0 3 c 2 1.0 4.0 NaN 4.0 4.0 4.0 4.0 4.0 4 c 8 2.0 16.0 0.0 16.0 16.0 16.0 16.0 16.0 Another groupby() method worth mentioning is agg(), which lets you run a bunch of different functions on your DataFrame simultaneously. For example, we can generate a simple statistical summary of the dataset as follows: 1data.groupby('col3').col1.agg([len, min, max]) .dataframe tbody tr th:only-of-type { vertical-align: middle; } .dataframe tbody tr th { vertical-align: top; } .dataframe thead th { text-align: right; } len min max col3 a 2 1 3 b 1 5 5 c 3 2 8 Effective use of groupby() will allow you to do lots of really powerful things with your dataset. Sorting sort_values() 1data.sort_values(by=[\"col1\"], ascending=False) .dataframe tbody tr th:only-of-type { vertical-align: middle; } .dataframe tbody tr th { vertical-align: top; } .dataframe thead th { text-align: right; } col1 col2 col3 1 8 16 c 5 8 16 c 4 5 10 b 3 3 6 a 2 2 4 c 0 1 2 a sort_index() 1data.sort_index(by=[\"col1\"], ascending=False) .dataframe tbody tr th:only-of-type { vertical-align: middle; } .dataframe tbody tr th { vertical-align: top; } .dataframe thead th { text-align: right; } col1 col2 col3 1 8 16 c 5 8 16 c 4 5 10 b 3 3 6 a 2 2 4 c 0 1 2 a Missing data & Replace Entries missing values are given the value NaN, short for \"Not a Number\". For technical reasons these NaN values are always of the float64 dtype. Pandas provides some methods specific to missing data. To select NaN entries you can use pd.isnull() (or its companion pd.notnull()). This is meant to be used thusly: 12data.loc[pd.isnull(data.col1)]# data.col1.isnull() is equivalent to pd.isnull(data.col1) .dataframe tbody tr th:only-of-type { vertical-align: middle; } .dataframe tbody tr th { vertical-align: top; } .dataframe thead th { text-align: right; } col1 col2 col3 Replacing missing values is a common operation. Pandas provides a really handy method for this problem: fillna(). fillna() provides a few different strategies for mitigating such data. For example, we can simply replace each NaN with an \"Unknown\": 1data.col1.fillna(\"Unknown\") 0 1 1 8 2 2 3 3 4 5 5 8 Name: col1, dtype: int64 Alternatively, replace() function is used widely. We now replace all 'a' to 'b' in col3. 1data.col3.replace('a', 'b') 0 b 1 c 2 c 3 b 4 b 5 c Name: col3, dtype: object Renaming rename() function lets you change index names and/or column names 1data.rename(columns={'col1': 'column1', 'col2': 'column2'}) .dataframe tbody tr th:only-of-type { vertical-align: middle; } .dataframe tbody tr th { vertical-align: top; } .dataframe thead th { text-align: right; } column1 column2 col3 0 1 2 a 1 8 16 c 2 2 4 c 3 3 6 a 4 5 10 b 5 8 16 c 1data.rename(index={1: 'row1', 4: 'row4'}) .dataframe tbody tr th:only-of-type { vertical-align: middle; } .dataframe tbody tr th { vertical-align: top; } .dataframe thead th { text-align: right; } col1 col2 col3 0 1 2 a row1 8 16 c 2 2 4 c 3 3 6 a row4 5 10 b 5 8 16 c rename_axis() function can give name to data's Title and Index 1data.rename_axis('index', axis='rows').rename_axis('fields', axis='columns') .dataframe tbody tr th:only-of-type { vertical-align: middle; } .dataframe tbody tr th { vertical-align: top; } .dataframe thead th { text-align: right; } fields col1 col2 col3 index 0 1 2 a 1 8 16 c 2 2 4 c 3 3 6 a 4 5 10 b 5 8 16 c Combining concat() 1pd.concat([data, data]) .dataframe tbody tr th:only-of-type { vertical-align: middle; } .dataframe tbody tr th { vertical-align: top; } .dataframe thead th { text-align: right; } col1 col2 col3 0 1 2 a 1 8 16 c 2 2 4 c 3 3 6 a 4 5 10 b 5 8 16 c 0 1 2 a 1 8 16 c 2 2 4 c 3 3 6 a 4 5 10 b 5 8 16 c join() 1data.join(data, lsuffix='lll', rsuffix='rrr') .dataframe tbody tr th:only-of-type { vertical-align: middle; } .dataframe tbody tr th { vertical-align: top; } .dataframe thead th { text-align: right; } col1lll col2lll col3lll col1rrr col2rrr col3rrr 0 1 2 a 1 2 a 1 8 16 c 8 16 c 2 2 4 c 2 4 c 3 3 6 a 3 6 a 4 5 10 b 5 10 b 5 8 16 c 8 16 c","categories":[{"name":"Data Science","slug":"Data-Science","permalink":"https://godway999.github.io/categories/Data-Science/"}],"tags":[]},{"title":"RL4:Dynamic Programming","slug":"RL4","date":"2020-03-02T06:05:03.000Z","updated":"2020-03-17T13:05:23.878Z","comments":true,"path":"2020/03/02/RL4/","link":"","permalink":"https://godway999.github.io/2020/03/02/RL4/","excerpt":"","text":"Refer from Reinforcement Learning An Introduction (2nd) and Reinforcement Learning specialization on Coursera by University of Alberta & Alberta Machine Intelligence Institute The key idea of DP, and reinforcement learning generally, is the use of value functions to orgnize and structure the search for good policy. The limitation of DP is that we must know the dynamic programing of the environment, which impossible to know in most of the time. Policy Evaluation is the tasks of determining the state-value function \\(v_\\pi\\) for a particular policy \\(\\pi\\) Policy Improvement is the task of improving an existed policy on given state values. Policy Control is the iteration of combining evaluation and improvement to get the optimal policy. Policy Evaluation(Prediction) The aim of the policy evaluation is to calculate value functions. Its idea is to change the bellman equation into an update rule. \\[ \\begin{eqnarray*} v_{k+1}(s) &\\doteq&\\sum_a\\pi(a|s) q_k(s,a)\\\\ &=&\\sum_a\\pi(a|s) \\sum_{s',r}p(s',r|s,a)(r+\\gamma v_k(s'))\\tag{4.1} \\end{eqnarray*} \\] We arbitrarily choose inital value for each state and the terminal state, if any, must be given value 0 and never be updated. Indeed, the sequence \\(\\{vk\\}\\) can be shown in general to converge to \\(v_\\pi\\) as \\(k\\rightarrow\\infty\\) under the same conditions that guarantee the existence of \\(v_\\pi\\). This algorithm is called iterative policy evaluation. We call this kind of operation an expected update. All the updates done in DP algorithms are called expected updates because they are based on an expectation over all possible next states rather than on a sample next state. Let's consider the \\(4\\times4\\) gride world below. Action: up, left, down, right. State: shadow blocks for terminal states and white blocks with numbers for non-terminal states. Reward: all transitions for a reward -1. Policy: random move policy(four actions have equal probabilities to choose at each state) With \\(\\theta = 0.001\\), we finally get this. Policy Improvement It is obvious that after we calculate state-value functions, the aim of the policy improvement is to improve the current policy \\(\\pi\\). Its idea is to change \\(\\pi\\) towards the optimal policy a little step. We call this policy improvement theorem\\((4.2)\\). \\(\\pi'\\) is the next new policy and both \\(\\pi\\) and \\(\\pi'\\) are deterministic policy. \\[ q_\\pi(s, \\pi'(s)) \\ge v_\\pi(s),\\ \\forall s\\in \\mathbf{S}\\tag{4.2}\\\\ \\Rightarrow v_\\pi'(s)) \\ge v_\\pi(s) \\] The premise of improvement is \\[ q_\\pi(s, \\pi'(s)) > q_\\pi(s, \\pi(s)), \\ \\exists s\\in\\mathbf{S} \\] AS well as this condition is avaliable, the new policy can always be a strictly improvement over \\(\\pi\\) unless \\(\\pi\\) is already optimal. Obviously we can get \\(\\pi'\\) by greedy selection of action values at each state. \\[ \\begin{eqnarray*} \\pi'(s) &=&\\mathop{argmax}_a q_\\pi(s,a)\\\\ &=&\\mathop{argmax}_a \\sum_{s',r}p(s',r|s,a)(r+\\gamma v_\\pi(s'))\\tag{4.3} \\end{eqnarray*} \\] The process of making a new policy that improves on an original policy, by making it greedy with respect to the value function of the original policy, is called policy improvement. Notice that from \\((4.3)\\) we actually get an \"optimal policy\" based on current state values (formal optimal policy establish on \\(v_*\\)). We can imagine if all our value function can hold for optimal bellman equation, then the current policy must be the optimal policy \\(\\pi_*\\). The gride world example is so simple that we just get the optimal policy after once improvement. we can notice even though we already get optimal policy but state values can still change (not converge). Policy Iteration(Control) Once a policy, \\(\\pi\\), has been improved using \\(v_\\pi\\) to yield a better policy, \\(\\pi'\\), we can then compute \\(v_\\pi'\\) and improve it again to yield an even better \\(\\pi''\\). Through alternating evaluation and improvement, we can thus obtain a sequence of monotonically improving policies and value functions \\[ \\pi_1 \\mathop{\\rightarrow}^E v_{\\pi_1} \\mathop{\\rightarrow}^I \\pi_2 \\mathop{\\rightarrow}^E v_{\\pi_2} \\mathop{\\rightarrow}^I \\pi_3 \\mathop{\\rightarrow}^E ... \\mathop{\\rightarrow}^I \\pi_* \\mathop{\\rightarrow}^E v_{\\pi_*} \\mathop{\\rightarrow}^I \\pi_* \\] This way of finding an optimal policy is called policy iteration. It follows a sequcence of better and better policies and value functions until it reaches the optimal policy and accosiated optimal value function. Here is a simple algorithnm for policy iteration with iterative policy evaluation Generalized Policy Iteration One big problem of above policy iteration algorithnm is that we first have to wait for the convergence of policy evaluation and then improve policy. This waste so much time and its efficience is low. The generalized policy iteration(GPI) flex the process and still gaurantee convergence of policy iteration. In each step, we don't have to reach the boundary but just incomplete steps towards each boundary. Value Iteration Value iteration is a special case of GPI as well as the policy iteration. In this case, we don't have to wait for completely finishing of policy evaluation. We stop after update evaluation one sweep (one update of each state). It combines policy evaluation and improvement by changing bellman optimality equation into an update rule. \\[ \\begin{eqnarray*} v_{k+1}(s) &\\doteq&\\mathop{max}_a q_k(s,a)\\\\ &=&\\mathop{max}_a \\sum_{s',r}p(s',r|s,a)(r+\\gamma v_k(s'))\\tag{4.4} \\end{eqnarray*} \\] Value iteration effectively combines, in each of its sweeps, one sweep of policy evaluation and one sweep of policy improvement. Faster convergence is often achieved by interposing multiple policy evaluation sweeps between each policy improvement sweep. Asynchronous DP synchronous DP: in each iteration, sweep all states and update them all. asynchronous DP: in each iteration, just update some of states and update in any order When state space is too large, sometimes it's impossible to use synchronous method to update all states. Efficiency of Dynamic Programming DP may not be practical for very large problems, but compared with other methods for solving MDPs (like linear programing or brute search), DP methods are actually quite efficient. If \\(n\\) and \\(k\\) denote the number of states and actions, this means that a DP method takes a number of computational operations that is less than some polynomial function of \\(n\\) and \\(k\\). A DP method is guaranteed to find an optimal policy in polynomial time even though the total number of (deterministic) policies is \\(k^n\\). Here comes to the curse of demensionality: The size of state space grows exponentially as the number of relevant features increase. This is not an issue with DP, but an inherent complexity of the problem. One limitation of DP is that DP requires a complete and accurate model of the environment.","categories":[{"name":"RL","slug":"RL","permalink":"https://godway999.github.io/categories/RL/"}],"tags":[]},{"title":"Git基本操作汇总","slug":"Others5","date":"2020-02-29T09:05:25.000Z","updated":"2020-02-29T09:16:59.821Z","comments":true,"path":"2020/02/29/Others5/","link":"","permalink":"https://godway999.github.io/2020/02/29/Others5/","excerpt":"","text":"Git流程图 Git操作","categories":[{"name":"Others","slug":"Others","permalink":"https://godway999.github.io/categories/Others/"}],"tags":[{"name":"Git","slug":"Git","permalink":"https://godway999.github.io/tags/Git/"}]},{"title":"RL3:Value Functions & Bellman Equations","slug":"RL3","date":"2020-02-29T03:14:01.000Z","updated":"2020-03-17T08:03:20.494Z","comments":true,"path":"2020/02/29/RL3/","link":"","permalink":"https://godway999.github.io/2020/02/29/RL3/","excerpt":"","text":"Refer from Reinforcement Learning An Introduction (2nd) and Reinforcement Learning specialization on Coursera by University of Alberta & Alberta Machine Intelligence Institute Policies and Value Functions Policy Formally, a policy is a mapping from states to probabilities of selecting each possible action. deterministic policy, denote \\(\\pi(s)=a\\): one state correspond to one action stochastic policy, \\(\\pi(a|s)\\): a probability distribution over all visable actions It's important that policies depend only on the current state, not on other things like time or previous states. State-value Function Almost all reinforcement learning algorithms involve estimating value functions -- functions of states (or of state–action pairs) that estimate how good it is for the agent to be in a given state (or how good it is to perform a given action in a given state), which means value function predicts reward into future. The value function of a state \\(s\\) under a policy \\(\\pi\\), denoted \\(v_\\pi(s)\\), is the expected return when starting in \\(s\\) and following \\(\\pi\\) thereafter. For MDPs, we can define \\(v_\\pi\\) formally by \\[v_\\pi(s)\\doteq \\mathbb{E}_\\pi[G_t|S_t=s]=\\mathbb{E}_\\pi[\\sum_{k=0}^\\infty \\gamma^kR_{t+k+1}|S_t=s],\\ for\\ all\\ s\\in \\mathbf{S}\\] We call the function \\(v_\\pi\\) the state-value function for policy \\(\\pi\\) Action-value Function Similarly, we define the value of taking action \\(a\\) in state \\(s\\) under a policy \\(\\pi\\), denoted \\(q_\\pi(s,a)\\), as the expected return starting from \\(s\\), taking the action \\(a\\), and thereafter following policy \\(\\pi\\): \\[q_\\pi(s,a)\\doteq \\mathbb{E}_\\pi[G_t|S_t=s,A_t=a]=\\mathbb{E}_\\pi[\\sum_{k=0}^\\infty \\gamma^kR_{t+k+1}|S_t=s,A_t=a]\\] We call the function \\(q_\\pi\\) the **action-value function for policy *, Bellman Equations Transform Between \\(v_\\pi\\) And \\(q_\\pi\\) Through the given diagram, we can derivate an equation for \\(v_\\pi\\) in terms of \\(q_\\pi\\) and \\(\\pi\\). \\[ \\begin{eqnarray*} v_\\pi(s) &=&\\mathbb{E}_\\pi[G_t|S_t=s]\\\\ &=&\\sum_a\\pi(a|s)\\mathbb{E}[G_t|S_t=s,A_t=a]\\\\ &=&\\sum_a\\pi(a|s)q(s,a)\\tag{3.1} \\end{eqnarray*} \\] Recall that \\(G_t=R_{t+1}+\\gamma G_{t+1}\\). With given diagram below, we can derivate an equation for \\(q_\\pi\\) in terms of \\(v_\\pi\\) and \\(p(s',r|s,a)\\). (use markov property to simplify original equation) \\[ \\begin{eqnarray*} q_\\pi(s,a) &=&\\mathbb{E}_\\pi[G_t|S_t=s,A_t=a]\\\\ &=&\\mathbb{E}_\\pi[R_{t+1}+\\gamma G_{t+1}]\\\\ &=&\\sum_{s',r}p(s',r|s,a)(r+\\gamma \\mathbb{E}_\\pi[G_{t+1}|S_{t+1}=s'])\\\\ &=&\\sum_{s',r}p(s',r|s,a)(r+\\gamma v_\\pi(s'))\\tag{3.2} \\end{eqnarray*} \\] Bellman Equations for \\(v_\\pi\\) Bellamn equation allows us to relate the value of the current state to the value of future states without waiting to observe all the future rewards. With \\((3.1),(3.2)\\), we can easiy get bellamn equation for \\(v_\\pi\\) \\[ \\begin{eqnarray*} v_\\pi(s) &=&\\sum_a\\pi(a|s)q(s,a)\\\\ &=&\\sum_a\\pi(a|s)\\sum_{s',r}p(s',r|s,a)(r+\\gamma v_\\pi(s'))\\tag{3.3} \\end{eqnarray*} \\] \\(s'\\) here stands for next state. Bellamn equation expresses a relationship between the value of a state and the values of its successor states (next state). You can get a more intiutive understanding about how this equation forms though its backup diagram below: we first choose actions through policy and then transites to a successor state with corresponding reward under environment dynamics. The open circles represent state nodes and solid circles represent action nodes. Bellman Equations For \\(q_\\pi\\) With \\((3.1),(3.2)\\), we can easiy get bellamn equation for \\(q_\\pi\\) \\[ \\begin{eqnarray*} q_\\pi(s,a) &=&\\sum_{s',r}p(s',r|s,a)(r+\\gamma v_\\pi(s'))\\\\ &=&\\sum_{s',r}p(s',r|s,a)(r+\\gamma\\sum_{a'} q_\\pi(s',a'))\\tag{3.4} \\end{eqnarray*} \\] \\(a'\\) here stands for actions under possible state \\(s'\\). Similarly, this equation express a relationship betweeen the value of an action and the values of actions under possible successor state \\(s'\\) An Example of Value Function: Grideworld State: each grid (totally 25 states) Action: north, south, east, and west Reward: actions that would take the agent off the grid leave its location unchanged, but also result in a reward of -1. Other actions results in a reward 0. Every time the agent moves any directions at position A would be transited to A' with reward +10. This is the same to B and B' except for reward +5. Policy: random policy, each direction has equal probability, 25%. \\(\\gamma=0.9\\) Now, just for curious, we can verify the \\(v_\\pi(s)\\) bellman equation in this example. Let's say we choose center state. \\[(0.7\\times0.9+0)\\times0.25+(2.3\\times0.9+0)\\times0.25+(0.4\\times0.9+0)\\times0.25\\\\+(-0.4\\times0.9+0)\\times0.25=0.69\\approx0.7\\] Why Bellman Equations? We use bellman equations to calculate \\(v_\\pi(s)\\) for all \\(s\\in \\mathbf{S}\\) by solving the system of linear equations. Still the previous example, gride world. It has 25 states and we get 25 unknown parameters. For each state we can get a bellman equation, therefore we get 25 equations. Through 25 equations, we sovle them to obtain 25 state values. But bellman equation is not pragmatic for many reasons. One of them is that sometimes the number of states is too large and it's impossible to calculate results in a short time. It can only solve small MDPs. Optimality (Optimal Policies & Value Functions) Optimal Policy A policy \\(\\pi\\) is defined to be better than or equal to a policy \\(\\pi'\\) if its expected return is greater than or equal to that of \\(\\pi'\\) for all states. In other words, \\[\\pi>\\pi' \\ \\ iff\\ v_\\pi(s)\\ge v_{\\pi'}(s)\\ for\\ all\\ s \\in \\mathbf{S}\\] There is always at least one deterministic policy that is better than or equal to all other policies. This is an optimal policy. Although there may be more than one, we denote all the optimal policies by \\(\\pi_*\\). They share the same state-value function, called the optimal state-value function, denoted \\(v_*\\), and the same optimal action-value function, denoted \\(q_*\\) \\[v_*(s)\\doteq \\mathop{max}_\\pi\\ v_\\pi(s)\\\\ q_*(s,a)\\doteq \\mathop{max}_\\pi\\ q_\\pi(s,a)\\\\ for\\ all\\ s\\in \\mathbf{S},a\\in \\mathbf{A}\\] Optimal Value Functions Because the optimal policy \\(\\pi_*\\) is a deterministic policy, the optimal action \\(a_*\\) with \\(\\pi(a_*|s)\\) equals to 1 and all other actions' probability equal to 0. We can re-write \\(v_*\\) with bellman equation as below, called bellman optimality equation for \\(v_*\\). \\[ \\begin{eqnarray*} v_*(s) &=&\\mathop{max}_\\pi\\ v_\\pi(s)\\\\ &=&\\mathop{max}_a \\mathbb{E}[R_{t+1}+\\gamma v_*(S_{t+1})|S_t=s,A_t=a]\\\\ &=&\\mathop{max}_a\\ \\sum_{s',r}p(s',r|s,a)(r+\\gamma v_*(s'))\\tag{3.5} \\end{eqnarray*} \\] Similarly, bellman optimality equation for \\(q_*\\) is \\[ \\begin{eqnarray*} q_*(s,a) &=&\\mathop{max}_\\pi\\ q_\\pi(s,a)\\\\ &=&\\mathbb{E}[R_{t+1}+\\gamma \\mathop{max}_{a'}\\ q_*(S_{t+1},a')|S_t=s,A_t=a]\\\\ &=&\\sum_{s',r}p(s',r|s,a)(r+\\gamma \\mathop{max}_{a'}\\ q_*(s',a'))\\tag{3.6} \\end{eqnarray*} \\] The bellman optimality equations relate the value of a state or state-action pair, to it's possible successors under any optimal policy. Unfortunately, the \\(max\\) funtion here is not linear, we cannot through linear system solver to directly solve bellman optimality equation to obtain all \\(v_*\\) in MDPs. Although, in principle, one can use a variety of methods for solving systems of nonlinear equations, it is not recommended due to its extreme computational cost. Get Optimal Policy Once one has \\(v_*\\), it is relatively easy to determine an optimal policy. Because, for each state \\(s\\), there will be one or more actions at which the maximum is obtained in the Bellman optimality equation. That is to say any policy that is greedy with respect to the optimal evaluation function \\(v_*\\) is an optimal policy. Having \\(q_*\\) makes choosing optimal actions even easier. The action-value function effectively caches the results of all one-step-ahead searches.","categories":[{"name":"RL","slug":"RL","permalink":"https://godway999.github.io/categories/RL/"}],"tags":[]},{"title":"RL2:Markov Decision Processes","slug":"RL2","date":"2020-02-28T09:21:31.000Z","updated":"2020-03-10T15:58:11.964Z","comments":true,"path":"2020/02/28/RL2/","link":"","permalink":"https://godway999.github.io/2020/02/28/RL2/","excerpt":"","text":"Refer from Reinforcement Learning An Introduction (2nd) and Reinforcement Learning specialization on Coursera by University of Alberta & Alberta Machine Intelligence Institute Introduction to Markov Decision Processes Definition of MDP MDPs are meant to be a straightforward framing of the problem of learning from interaction to achieve a goal. Here are the key element in discribing a MDP agent: the learner and the decision maker environment: the thing a agent interacts with, comprising everything outside the agent action: selected by the agent to interact with the environment reward: special numerical values that the agent seeks to maximize over time through its choice of actions. the whole interacting process is precisely simplified as follow More specifically, the agent and the environment interact at each of a sequence of discrete time steps, \\(t=0,1,2,3,...\\) At each time step \\(t\\), the agent recives some representation of the environment's state, \\(S_t \\in \\mathbf{S}\\), and on that basis selects an action, \\(A_t \\in \\mathbf{A}(s)\\). One time step later, in part as a consequence of its action, the agent receives a numerical reward, \\(R_{t+1} \\in \\mathbf{R}\\subset \\mathbb{R}\\), and finds itself in a new state, \\(S_{t+1}\\). The MDP and agent together thereby give rise to a sequence or trajectory that begins like this: In a finite MDP, the sets of states, actions, and rewards (\\(\\mathbf{S}\\), \\(\\mathbf{A}\\), and \\(\\mathbf{R}\\)) all have a finite number of elements. In this case, the random variables \\(R_t\\) and \\(S_t\\) have well defined discrete probability distributions dependent only on the preceding state and action. That is, for particular values of these random variables, \\(s' \\in \\mathbf{S}\\) and \\(r \\in \\mathbf{R}\\), there is a probability of those values occurring at time t, given particular values of the preceding state and action: \\[p(s',r|s,a)\\doteq P(S_t=s', R_t=r\\ | \\ S_{t-1}=s, A_{t-1}=a)\\tag{2.1}\\] for all \\(s',s \\in \\mathbf{S}\\), \\(r \\in \\mathbf{R}\\), and \\(a \\in \\mathbf{A}(s)\\). The function \\(p\\) defines the dynamics of the MDP. \\[p:\\ \\mathbf{S}\\times \\mathbf{R}\\times \\mathbf{S}\\times \\mathbf{A}\\rightarrow [0,1]\\] With \\(p(s',r|s,a)\\), note that future state and reward only depends on the current state and action. This is called the Markov property. It means that the present state is sufficient and remembering earlier states would not improve predictions about the future. The MDP framework is a considerable abstraction of the problem of goal-directed learning from interaction. It can be used to formalize a wide variety of sequential decision-making problem. This also means that any problem of learning goal-directed behavior can be reduced to three signals passing back and forth between an agent and its environment: actions, states, rewards. An Example of MDP Here is an example of finite MDP, Recycling Robot. We can write down the transition probabilities and the expected rewards, with dynamics as indicated below. We can show it in another useful way called trasition graph There are two kinds of nodes: state nodes and action nodes. The key point here is that the agent fisrtly chooses an action and then transits to a state with corresponding probability. Goal of Reinforcement Learning The Goal of RL In reinforcement learning, reward captures the notion of short-term gain. The objective however, is to learn a policy that achieves the most reward in the long run. With this premise, we denote the return at time step \\(t\\) as \\(G_t\\) \\[G_t\\doteq R_{t+1}+R_{t+2}+R_{t+3}+...\\tag{2.2}\\] We intuitively want to maxmize \\(G_t\\) at each time step. However, \\(G_t\\) is a random variable because the dynamics of the MDP can be stochastic. That's why we define the goal of an agent is to maxmize the expected return \\[\\mathbb{E}[G_t] = \\mathbb{E}[R_{t+1}+R_{t+2}+R_{t+3}+...]\\tag{2.3}\\] The Reward Hypothesis The Reinforcement Learning Hypothesis can be expressed as this: Intelligent behavior araises from the actions of an individual seeking to maximize its received reward signals in a complex and challenging world. There are two research programs: Identify where reward signals come from. (what reward the agent should optimize) Develop algorithms that search the space of action to maximize reward signals. Informally, the agent’s goal is to maximize the total amount of reward it receives. This means maximizing not immediate reward, but cumulative reward in the long run. We can clearly state this informal idea as the reward hypothesis: That all of what we mean by goals and purposes can be well thought of as the maximization of the expected value of the cumulative sum of a received scalar signal (called reward). But how can we define reward? This is a trick problem. To use goals as rewards, we have some representations: goal-reward representation: 1 for achieving goal, 0 otherwise action-penalty representation: -1 for not achieving goal, 0 once goal reached Both of representations have its own limitation. They lack of some middel information to tell the agent how to achieve the goal as our expectation. Episodic Tasks And Continuing Tasks Episodic Tasks In an episodic task, the agent-environment interaction breaks up into episodes. Episodes are indepedent and each episode ends in a terminal state at time step \\(T\\). In this situation, time step is finite and we change (2.2) as \\[G_t \\doteq R_{t+1}+R_{t+2}+R_{t+1}+...+R_T\\tag{2.4}\\] Continuing Tasks The interaction between agent-environment goes on continually and there is no terminal state. In this situation, time step is infinite and \\(G_t\\) is the same in \\((2.2)\\) \\[G_t \\doteq R_{t+1}+R_{t+2}+R_{t+3}+...\\] But here comes to the problem: \\(G_t\\) could be \\(\\infty\\) and impossible to calculate. Therefore, we should make \\(G_t\\) finite, which by using discounting method. Discounting Discount the rewards in the future by \\(\\gamma\\) called discount rate, where \\(\\gamma \\in [0,1]\\) \\[ \\begin{eqnarray*} G_t &\\doteq& R_{t+1}+\\gamma R_{t+2}+\\gamma^2R_{t+3}+...+\\gamma^{k-1}R_{t+k}+...\\\\ &=&\\sum_{k=0}^\\infty \\gamma^kR_{t+k+1}\\tag{2.5} \\end{eqnarray*} \\] We can also re-write \\(G_t\\) in the recursive version \\[G_t = R_{t+1}+\\gamma G_{t+1}\\tag{2.6}\\] To prove \\(G_t\\) is finite, let's assume \\(R_{max}\\) is the maximum reward the agent can receive \\[ \\begin{eqnarray*} G_t=\\sum_{k=0}^\\infty \\gamma^kR_{t+k+1}&\\le& \\sum_{k=0}^\\infty \\gamma^kR_{max}\\\\ &=&R_{max}\\sum_{k=0}^\\infty \\gamma^k\\\\ &=&R_{max}\\times \\frac{1}{1-\\gamma} \\end{eqnarray*} \\] It proves that \\(G_t\\) now is finite. To Specify, let's talk about \\(\\gamma=0\\) and \\(\\gamma=1\\). \\(\\gamma=0\\Rightarrow G_t=R_t\\) : agent only cares about immediate reward. (short-sighted agent) \\(\\gamma\\rightarrow1\\) : agent takes future rewards into account more strongly. (far-sighted agent) Unified Episodic and Continuing Tasks we can consider episode termination to be the entering of a special absorbing state that transitions only to itself and that generates only rewards of zero. For example, consider the state transition diagram: Thus, we can informally regard epsoidic tasks as continuing task.","categories":[{"name":"RL","slug":"RL","permalink":"https://godway999.github.io/categories/RL/"}],"tags":[]},{"title":"RL1:K-armed Bandits Problem","slug":"RL1","date":"2020-02-27T04:35:49.000Z","updated":"2020-03-16T09:54:30.871Z","comments":true,"path":"2020/02/27/RL1/","link":"","permalink":"https://godway999.github.io/2020/02/27/RL1/","excerpt":"","text":"Refer from Reinforcement Learning An Introduction (2nd) and Reinforcement Learning specialization on Coursera by University of Alberta & Alberta Machine Intelligence Institute The K-Armed Bandit Problem In the k-armed bandit problem, we have an agent who choooses between \"k\" action and recieves a reward based on the action it chooses. The goal of the agent is to maximize the expected total reward over some time period, or time steps. In a word, decision making under uncertainty can be formalized by the k-armed bandit problem Action Values the value of an action is the expected reward when that action is taken \\[ \\begin{eqnarray*} q_*(a) &\\doteq& \\mathbb{E}[R_t\\ | \\ A_t = a],\\ \\forall a \\in \\mathbf{A}\\\\ &=&\\sum_rp(r|a)r\\tag{1.1} \\end{eqnarray*} \\] To clearly explain this, the reward of an action may not be fixed so the reward may comfirm to a uniform distribution or normal distribution. Here is an example to illustrate this process Action Selection Remember that the agent's goal is to maximize the expected total amount of reward it recieves. We can call this procedure the argmax (the argument \"a\" which maximizes function \\(q_*\\)) \\[\\mathop{argmax}_a \\ q_*(a)\\] It is clear that if you know the value of each action, then it would be trivial to solve the k-armed bandit problem: you would always select the action with highest value. Thus, the problem here is that the agent do not know the action values with certainty. It only have to estimate the action values. But how to estimate action-values? What to Learn? Estimating Action Values Sample-Average One way to estimate \\(q_*\\) is to compute a sample-average. Here we denote the estimated value of action \\(a\\) at time step \\(t\\) as \\(Q_t(a)\\). We would like \\(Q_t(a)\\) to be close to \\(q_*(a)\\). \\[Q_t(a) \\doteq \\frac{\\sum_{i=1}^{t-1}R_i}{t-1}\\tag{1.2}\\] Notice that we use \\(t-1\\) because we are calculating \\(Q_t(a)\\) with history prior to \\(t\\). And to be clear, \\(t\\) has separate corresponding value for each action. Here is an example of medical trail. And we can simplify \\(Q_t\\) by extending it in incremental update rule \\[ \\begin{eqnarray*} Q_{t+1} &=&\\frac{1}{t}\\sum_{i=1}^tR_i\\\\ &=&\\frac{1}{t}(R_t+(t-1)\\frac{1}{t-1}\\sum_{i=1}^{t-1}R_i)\\\\ &=&\\frac{1}{t}(R_t+(t-1)Q_t)\\\\ &=&Q_t+\\frac{1}{t}(R_t-Q_t)\\tag{1.3} \\end{eqnarray*} \\] To generalize it, we replace \\(\\frac{1}{t}\\) with \\(\\alpha_t\\) to represent stepsize and it's easy to know \\(\\alpha_t \\in [0,1]\\) \\[Q_{t+1}=Q_t+\\alpha_t(R_t-Q_t)\\tag{1.4}\\] And it can also express as below \\[NewEstimate \\leftarrow OldEstimate\\ +\\ StepSize(Target\\ -\\ OldEstimate)\\] The expression \\((Target-OldEstimate)\\) is an error in the estimate. It is reduced by taking a step toward the “Target.” The target is presumed to indicate a desirable direction in which to move, though it may be noisy. In the case above, for example, the target is the nth reward. Nonstationary Problem What if the reward distribution of each action is changing over time? In this situation, what we learn form history may not correctly represent current state due to changing of reward distribution. In such cases it makes sense to give more weight to recent rewards than to long-past rewards because recent information reflect changing more accurate. To do so, we can use a fixed stepsize,like 0.5, instead of \\(\\frac{1}{t}\\). This can lead to decaying exponently past reward. \\[Q_{t+1}=Q_t+\\alpha_t(R_t-Q_t)=\\alpha_tR_t+(1-\\alpha_t)Q_t\\tag{1.5}\\] As \\(\\alpha_t\\) increases, the more \\(R_t\\) contributes to \\(Q_{t+1}\\) and the less for \\(Q_t\\). Greedy Action At each time step, the agent could alway choose the action with the highest action value estimated by history. And this is called greedy action. \\[a_g = \\mathop{argmax}_a\\ \\ Q(a)\\] Seemingly we can through greedy action to archieve our goal, maxmizing expected total reward. But there is still a problem exists: how does the agent know its estimation about each action is correctly approximating to the real distribution? Greedy action is greatly impact by initial action value. Why does the agent know other actions are worse than greedy action even trying them only a few times? I think the agent should spend some time trying other actions instead of greedy action. And this come to the exploration and exploitation tradeoff Exploration vs. Exploitation Tradeoff Exploration and Exploitation Dilemma Exploration: improve knowledge for long-term benefit Exploitation: exploit knowledge for short-term benefit The dilemma means: How do we choose when to exploit and when to explore? When we explore, we get more accurate estimates of our values. When we exploit, we might get more reward. We cannot however choose to do both simultaneously. Epsilon-Greedy Action Selection One very simple method for choosing between exploration and exploitation is to choose randomly. We could choose to exploit most of the time with a small chance of exploring. For instance, we could roll a dice. This is called \\(\\epsilon\\)-greedy action selection. We formulize it as below, where \\(\\epsilon \\in [0,1]\\) \\[ A_t\\leftarrow \\begin{cases} \\mathop{argmax}_a Q_t(a)\\ \\ \\ \\ \\ \\ \\ \\ 1-\\epsilon\\\\ \\\\ a\\sim Uniform(\\mathbf{A})\\ \\ \\ \\ \\ \\ \\epsilon \\end{cases} \\] Let's evaluate on 10-armed testbed We run each agent with different \\(\\epsilon\\) for 2000 independent runs, each run for 1000 time steps. Then we average 2000 runs to get the learning algorithm’s average behavior. The advantage of \\(\\epsilon\\)-greedy over greedy methods depends on the task. If the reward variance is large, like 10, then more explorations to detect best action is important. More detections give the agent more confidence to pick up optimal action. On the other hand, if the reward variance is zero, then greedy method would know the true value of each action after trying it once. Seemingly, in this case, greedy method would soon find the greedy action and it might perform best. But, this can not be guaranteed under nonstationary situations. Nonstation means the true values of the actions changed over time. In this case, exploration is needed to ensure that one of the nongreedy actions has not changed to become better than the greedy one. Optimistic Initial Values Optimistic initial values encourage early exploration. In real programing, don't intialize all acion values defaut to 0. Here is an example to show algorithm's performance by using this method. Limitation of optimistic inital values: Optimistic intial values only drive early exploration They are not will suited for nonstationary problems We may not know what the optimistic values should be Upper-Confidence Bound (UCB) Action Selection \\(\\epsilon\\)-greedy action selection forces the non-greedy actions to be tried, but indiscriminately and uniformly, with no preference for those that are nearly greedy or particularly uncertain. It would be better to select among the non-greedy actions according to their potential for actually being optimal, taking into account both how close their estimates are to being maximal and the uncertainties in those estimates. In upper-confidence bound(UCB) action selection, we follow the principle of optimism in the face of uncertainty. This simply means that if we are uncertain about something, we should optimistically assume that it is good. For instance, say we have these three actions with associated uncertainties. The larger confidence interval means bigger uncertainies. So the agent optimistically picks the action that has the highest upper bound, action 1. After that, this time, we should select action 2. The key idea in UCB is that it uses uncertainty or variance (sqrt root) in the value estimation for balancing exploration and exploitation. \\[A_t \\doteq \\mathop{argmax}_a [Q_t(a)+c\\sqrt{\\frac{\\ln{t}}{N_t(a)}}\\ ]\\] We can clearly see here how UCB combines exploration and exploitation. The first term in the sum represents the exploitation part, and the second term represents the exploration part. The constant parameter \\(c\\) is used to scale the extent of exploration. \\(N_t(a)\\) denotes the number of times that action \\(a\\) has been selected prior to time \\(t\\). The limitation of UCB is not practical for very huge state spaces. Summary The gap between k-armed bandit problem and the full reinforcement learning problem: there is no association between actions and situations(or states). Each selection of actions is non-contextual or independent. thers is no policy, which designate actions at each situation(or state). we summarize a complete learning curve by its average value over the 1000 steps; this value is proportional to the area under the learning curve. This kind of graph is called a parameter study.","categories":[{"name":"RL","slug":"RL","permalink":"https://godway999.github.io/categories/RL/"}],"tags":[]},{"title":"博弈论2:纯策略纳什均衡","slug":"Game2","date":"2020-02-25T03:23:24.000Z","updated":"2020-03-06T17:07:54.305Z","comments":true,"path":"2020/02/25/Game2/","link":"","permalink":"https://godway999.github.io/2020/02/25/Game2/","excerpt":"","text":"All materials come from Coursera《Game Theory》by Stanford University & The University of British Columbia Intro to nash equilibrium Attributes of nash equilibrium nobody has an incentive to deviate** from their actions if a nash equilibrium is achieved** each player's action maximizes his/her payoff given the actions of others a self-consistent or stable profile Pure Strategy Nash Equilibrium Pure Strategy And Mixed Strategy the informal definitions of pure strategy and mixed strategy are pure strategy: only one action is played with positive probability mixed strategy: more than one action is played with positive probability With a pure strategy, a player choose one action with 100% ensurance. While with a mixed strategy, a player can have a probability of 50% choosing action A and a probability of 50% choosing action B. In another word, player \\(i\\) chooses action \\(a_i\\) randomly from \\(A\\) with corresponding probability. Best Response The idea of Best Response: if you know what everyone else was going to do, it would be easy to pick your own action. Based on the previous lecture, \\(a\\) represents action profile, which organized by \\(n\\) players' action \\[a = (a_1, a_2,..., a_n)\\] Now we denote \\(a_{-i}\\), which means a sub action profile of other players act \\[a_{-i} = (a_1, a_2,..., a_{i-1}, a_{i+1},..., a_n)\\] Then we can re-define \\(a\\) as \\[a = (a_i, a_{-i})\\] Therefore, the definition of Best Response is showen below \\[a_i^* \\in BR(a_{-i}) \\ \\ iff \\ \\ \\forall a_i \\in A_i, u_i(a_i^*, a_{-i}) \\ge u_i(a_i, a_{-i})\\] That is to say, given \\(a_{-i}\\), \\(a_i^*\\) is the best response for player \\(i\\) to play. But in practice, no agent knows what the others will do, so we can't say about what actions will actually occur. The idea here is to look for stable action profiles, leading to equilibrium point. \\(a = (a_1, a_2,..., a_n)\\) is a (pure strategy) nash equilibrium iff \\(\\forall i,\\ a_i \\in BR(a_{-i})\\) Dominant Strategy generalize from actions to strategies Mixed Strategy Nash Equilibrium","categories":[{"name":"Game Theory","slug":"Game-Theory","permalink":"https://godway999.github.io/categories/Game-Theory/"}],"tags":[]},{"title":"Linux下常用指令","slug":"Others4","date":"2020-02-05T06:46:11.000Z","updated":"2020-02-29T09:03:22.383Z","comments":true,"path":"2020/02/05/Others4/","link":"","permalink":"https://godway999.github.io/2020/02/05/Others4/","excerpt":"","text":"top 查看系统进程 screen 12screen -S [TaskName] 创建一个名为TaskName的screenscreen -r(-x) [TaskName] 恢复(进入)名为TaskName的screen 快捷指令: 上下分屏:ctrl + a 再按shift + s 切换屏幕:ctrl + a 再按tab键 新建一个终端:ctrl + a 再按c du、df du = disk used 硬盘使用情况 df = disk free 硬盘剩余空间 123456789du -h [FileName] 查看指定文件大小df -hl 查看磁盘剩余空间df -h 查看每个根路径的分区大小du -sh [目录名] 返回该目录的大小du -sm [文件夹] 返回该文件夹总M数 find find命令是根据文件的属性进行查找,如文件名,文件大小,所有者,所属组,是否为空,访问时间,修改时间等 1find [location] -name [FileName] 在location下查找名字为FileName的文件 grep grep是根据文件的内容进行查找,会对文件的每一行按照给定的模式(patter)进行匹配查找 1grep [字符串] [File] 在File中按行匹配字符串 which、whereis which 查看可执行文件的位置 ,只有设置了环境变量的程序才可以用 whereis 寻找特定文件,只能用于查找二进制文件、源代码文件和man手册页 more/less 查看文件内容,当文件内容很大时比cat命令要好用 head、tail 123head(tail) -n 1000 [FileName] 显示FileName文件的前1000行(后1000行)tail -n +1000 [FileName] 显示FileName文件从1000行往后的内容tail -f [FileName] 追踪(follow)文件FileName free、swapoff、mkswap、swapon 查看内存状态命令,可以显示memory、swap、buffer/cache等的大小及使用状况 123456789free -h 查看内存状态swapoff -a 取消所有挂载的swap空间dd if=/dev/zero of=/var/swapfile bs=1M count=1024 在/var目录下创建大小为1G的文件用做swap空间mkswap /var/swapfile 格式化swap文件swapon /var/swapfile 挂载swap空间 netstat 查看网络状态(地址和端口号) 1netstat -tunlp 其中t(tcp)、u(udp),nlp分别是三个flag参数 tmux 详细内容参考 1234tmux new -s [NewSessionName] 创建标签为NewSessionName的新会话,默认数字index从0开始tmux attach -t [index/name] 恢复到index/name的会话连接tmux ls 查看所有会话tmux switch -t [index/name] 切换到index/name会话 快捷指令 : ctrl + b %: 左右分屏 ctrl + b “: 上下分屏 ctrl + b 空格: 左右分屏 ctrl + b 上下左右: 切换分屏","categories":[{"name":"Others","slug":"Others","permalink":"https://godway999.github.io/categories/Others/"}],"tags":[]},{"title":"博弈论1:为什么囚徒困境是一个困境?","slug":"Game1","date":"2020-01-20T11:48:16.000Z","updated":"2020-03-07T01:56:51.227Z","comments":true,"path":"2020/01/20/Game1/","link":"","permalink":"https://godway999.github.io/2020/01/20/Game1/","excerpt":"","text":"All materials come from Coursera《Game Theory》by Stanford University & The University of British Columbia 囚徒困境 两个囚犯现在被捕,警察将他们两个分别关在了不同的房间(囚犯之间互相无法交谈),警察为了让他们招供,对两个人分别说了这样一番话: 若你和他都选择不招供,则在我们目前已有证据的基础上,我们有信心将你们两个都判1年 若你选择招供告发他,而他不招供,那么我们将直接无罪释放你并且他会被判3年 若你和他都选择了招供,那问题就很简单了,你们将都被判2年 现在我们将上述规则以更简练的矩阵形式表示出来 其中C表示囚犯选择与对方合作(Cooperate)即不招供,D表示囚犯选择欺骗对方(Defect)即选择招供,左边的C和D代表囚犯1可以做的两个选择,同理上方的C和D代表囚犯2可以做的两个选择。举个例子,对于右上角的方格,表示囚犯1选择不招供(C)而囚犯2选择招供(D),结果囚犯1被判了3年而囚犯2无罪释放 为了进一步说明这个问题,我们先引入一些博弈论的基本概念 博弈的基本定义 博弈的基本元素有以下几个: 玩家(Players):做出决定的个体 行动(Actions):每个玩家可以做出怎样的行动 奖励/代价(Payoff):玩家做出每个行动之后会有怎样反馈(例如商人在股票最高点抛售这一行动可以获得最高的收益) 时序(Timing):事件发生的顺序(例如大家下棋时轮流交替移动棋子) 信息(information):当玩家做出行动时他们都知道什么信息(参与者对其他参与者的了解程度) 所以有限n人标准博弈的数学定义表示为\\(<N, \\mathbf{A}, u>\\)其中元素分别表示如下含义: 玩家的集合\\(N = \\{1, 2, ..., n\\}\\) 是一个大小为n的有限集合,用\\(i\\)标识 行动组合的全集\\(\\mathbf{A} = A_1 \\times A_2 \\times ... \\times A_n\\),其中\\(A_i\\)表示玩家\\(i\\)的行动集合,若用\\(a\\)表示一个行动组合(action profile),则有\\(a = (a_1, a_2, ..., a_n) \\in \\mathbf{A}\\) 效用(代价)函数组\\(u = (u_1, u_2, ..., u_n)\\),其中对于玩家\\(i\\),\\(u_i: \\mathbf{A} \\rightarrow \\mathbb{R}\\),特别注意 ,此处的\\(u_i\\)表示一个从行动组合集合\\(a \\in A\\)到实数\\(\\mathbf{R}\\)的映射 支配策略 我们在参与游戏的时会有一个要实现的目标(goal),通常情况下的目标为最大化自己的收益(payoff),但是也可以有别的目标(比如以让对方获得最小收益为目标) 为实现这个目标我们会有一个对应的策略(strategy),策略指导玩家该做出什么行动(或选择什么行动)。比如在囚徒困境中,囚犯的策略就是:做出怎样的选择(招供或不招供),以使自己被判的时间最短。这里每个囚犯有两个选择:与另一个囚犯合作(Cooperate)和欺骗另一个囚犯(Deceive),选择合作意味着不招供而欺骗意味着招供,所以每个囚犯都会思考,如果对方招供的话我该怎么选,如果对方不招供的话我又该怎么选?从而我们这里引入一个概念支配策略(dominant strategy) 支配策略:A dominant strategy for a player is one that produces the highest payoff of any strategy available for every possible action by the other players。通俗点讲就是:不管别人做出怎样的行动,我所做的选择都可以让我得到最大收益。还以囚徒困境举例 情况一:当囚犯2选择C不招供(下图红框),那么对于囚犯1来说:选C不招供那么自己会被判1年,而D招供那么自己可以无罪释放(下图绿框)。所以很显然,此时选D招供是最好的选择 情况二:当囚犯2选择D招供(下图红框),那么对于囚犯1来说:选C不招供那么自己会被判3年,而D招供那么自己会被判2年(下图绿框)。所以很显然,此时选D招供是最好的选择 综合上述两种情况,我们可以得出结论:不论囚犯2如何选择,囚犯1的最佳选择都是D招供(也就是囚犯1的支配策略)。同样的道理,由于囚犯1和囚犯2的地位是对称的,所以囚犯2的支配策略也是D招供 关于囚徒困境的结论 根据之前的支配策略的分析,两个囚犯的支配策略都是D招供,从而两个人都被判2年。而囚徒困境的令人诧异的地方也就出现于此,我们如果从一个上帝视角来看,很明显,两个囚犯的最佳选择明明是选择都不招供,这样两个人加起来判的时间是最少的,是全局最优解,但是如果从个人角度来分析,就会发现,无论如何他们两个都不会去选择一起合作不招供。这恰恰就是囚徒困境的背景————两个人无法交流即非合作博弈,其所谓的上帝视角其实是不存在的,因为将其推广到繁杂的现实,就会发现没有“上帝”可以看到整个全局,没有人的信息是全局的,从而从这个思想出发,反驳了亚当斯密的一个基本观点:所有人的最优选择会形成整个群体的最优选择,因为当所有人做到自己的最优时,对于整个社会来说可能是最坏的(两个囚犯加起来一共判了4年) 补充 囚徒困境的标准通式满足: \\[c > a > d > b\\]","categories":[{"name":"Game Theory","slug":"Game-Theory","permalink":"https://godway999.github.io/categories/Game-Theory/"}],"tags":[]},{"title":"统计学习方法——第十三章:无监督学习概论","slug":"ML13","date":"2020-01-17T13:55:39.000Z","updated":"2020-01-20T13:44:53.687Z","comments":true,"path":"2020/01/17/ML13/","link":"","permalink":"https://godway999.github.io/2020/01/17/ML13/","excerpt":"","text":"参考书目《统计学习方法(第2版)》 李航 著 无监督学习基本原理 无监督学习是从无标注的数据中学习数据的统计规律或者说内在结构的机器学习,主要包括聚类、降维、概率估计 无监督学习的基本想法是对给定数据(矩阵数据)进行某种“压缩”,从而找到数据的潜在结构。假定损失最小的压缩得到的结果就是最本质的结构 发掘数据的纵向结构,把相似的样本聚到同类,即对数据进行聚类 发掘数据的横向结构,把高维空间的向量转换为低维空间的向量,即对数据进行降维聚类 同时发掘数据的纵向和横向结构,假设数据由含有隐式结构的概率模型生成得到,从数据中学习该概率模型 三个基本问题 聚类 聚类(clustering)是将样本集合中相似的样本(实例)分配到相同的类,不相似的样本分配到不同的类。 聚类时,样本通常是欧氏空间中的向量,类别不是预先给定,而是从数据中自动发现,但类别的个数通常是预先给定的。样本之间的相似度或距离由 应用决定。 如果一个样本只能属于一个类,则称为硬聚类(硬聚类) \\[z_i = g_\\theta(x_i), i = 1,2,...,N\\] 如果一个样本可以属于多个类,则称为软聚类(软聚类) \\[P_\\theta(z_i|x_i), i = 1,2,...,N\\] 降维 降维(dimensionality reduction)是将训练数据中的样本(实例)从高维空间转换到低维空间 假设样本原本存在于低维空间,或者近似地存在于低维空间,通过降维则可以更好地表示样本数据的结构,即更好地表示样本之间的关系 高维空间通常是高维的欧氏空间,而低维空间是低维的欧氏空间或者流形(manifold) 从高维到低维的降维中,要保证样本中的信息损失最小 降维的模型是函数 \\[z_i = g_\\theta(x_i), i = 1,2,...,N\\] 其中\\(x_i \\in X\\)是样本的高维向量,\\(z_i \\in Z\\)是样本的低维向量,\\(\\theta\\)是参数,函数可以是线性函数也可以是非线性函数,降维的过程就是学习降维模型的过程 概率模型估计 概率模型估计(probility model estimation),简称概率估计,假设训练数据由一个概率模型生成,由训练数据学习概率模型的结构和参数。 概率模型的结构类型(或者说概率模型的集合事先给定),而模型的具体结构与参数从数据中自动学习。学习的目标是找到最有可能生成数据的结构和参数。 概率模型表示为条件概率分布 \\[P_\\theta(x|z)\\] 随机变量\\(x\\)表示观测数据,可以是连续变量也可以是离散变量,随机变量\\(z\\)表示隐式结构,是离散变量,随机变量\\(\\theta\\)表示参数。概率模型的一种特殊情况是隐式结构不存在,即满足 \\[P_\\theta(x|z) = P_\\theta(x)\\] 这时条件 概率分布估计变成概率分布估计,只要估计分布\\(P_\\theta(x)\\)的参数即可 无监督学习三要素 (1)模型: 函数\\[z = g_\\theta(x)\\],条件概率分布\\[P_\\theta(z|x)\\],或条件概率分布\\[P_\\theta(x|z)\\] (2)策略: 目标函数的优化 (3)算法: 迭代算法,通过迭代达到对目标函数的最优化","categories":[{"name":"机器学习","slug":"机器学习","permalink":"https://godway999.github.io/categories/机器学习/"}],"tags":[]},{"title":"Nvidia GPU 基本概念","slug":"GPU1","date":"2019-11-25T00:46:56.000Z","updated":"2019-11-25T02:36:25.216Z","comments":true,"path":"2019/11/25/GPU1/","link":"","permalink":"https://godway999.github.io/2019/11/25/GPU1/","excerpt":"","text":"Physical Architecture of GPU 下图为Nvidia官网上找的一个GPU主板的概念图,对应Device Device:与host做区分,可以理解为是指整个显卡 如下图所示(Nvidia Tesla P100),共包含60个SM(6GPC x 10SM) SM(Streaming Multiprocessor):等价于NUMA中的core的概念,由多个SP加上其他的一些硬件资源组成 其他硬件资源如:warp scheduler,register,shared memory等 同一个block中的warp一定分配给同一个SM 每个SM有自己独立的local L1 cache,但所有SM会共用Device的L2 cache 每个SM有自己的内部结构,如下图所示GP100(Nvidia Tesla P100)中的SM内部结构,在GP100里,每一个SM有左右两个SM Processing Block(SMP) SP(Streaming Processor):最基本的处理单元,也称为CUDA core,表示在上图中为绿色的小格子 相当于一个简易的CPU 内部包括控制单元Dispatch Port、Operand Collector,以及浮点计算单元FP Unit、整数计算单元Int Unit,另外还包括计算结果队列。当然还有Compare、Logic、Branch等 下图为SP(CUDA core)的内部结构 Software Concept in CUDA Thread:一个CUDA的并行程序会被分配到多个threads来执行 一个SP对应执行一个thread threadId在cuda中为三维的概念,在一个block中由(x, y, z)来唯一定位 Block:多个thread群组成一个block 同一个block中的threads可以同步,也可以通过shared memory通信 blockId在cuda中为二维的概念,在一个grid中由(x, y)来唯一定位 Grid:多个block构成grid 一个grid对应一个执行一个kernel函数 空间对应如下图所示 warp:执行任务的调度单元,同一时间一个SM只能运行一个warp 类比于CPU中的进程,当一个warp阻塞时,SM将切换执行另一个warp 当前CUDA的warp大小为32个线程。这里表明Nvidia的GPU执行粒度小,执行线程粒度越小,并行度越高,掩盖延迟的能力越强 同在一个warp中的线程,以不同数据资源执行相同的指令,即所谓的SIMT(Single Instruction Multiple Thread) CPU和GPU的结构对比 CPU是靠更大的缓存和复杂的逻辑控制(如流水线、乱序执行、指令预测和预处理等等)来掩饰延迟的 GPU是靠更高的并行度来掩饰延迟的 Others GPU在并发的warp之间切换是没什么消耗的,因为硬件资源早就被分配到所有thread和block,所以新调度的warp的状态已经存储在SM中了。不同于CPU,CPU切换线程需要保存/读取线程上下文(register内容),这是非常耗时的,而GPU为每个threads提供物理register,无需保存/读取上下文。 register和shared memory是SM的稀缺资源。CUDA将这些资源在程序执行前就分配给所有驻留在SM中的warp,并且整个程序执行周期都不再变动。因此这些有限的资源就会限制每个SM中active warp的数量,实验结果显示一个SM至少要存在6个active warp才能有效掩饰延迟 Reference Material CUDA编程——GPU架构,由sp,sm,thread,block,grid,warp说起 GPU高性能编程CUDA实战 Nvidia GPU架构 - Cuda Core,SM,SP CUDA编程——GPU架构,由sp,sm,thread,block,grid,warp说起 CUDA中grid、block、thread、warp与SM、SP的关系","categories":[{"name":"GPU","slug":"GPU","permalink":"https://godway999.github.io/categories/GPU/"}],"tags":[]},{"title":"Shell中的常用通配符,字符类","slug":"Others2","date":"2019-07-03T02:42:24.000Z","updated":"2019-07-03T02:49:35.347Z","comments":true,"path":"2019/07/03/Others2/","link":"","permalink":"https://godway999.github.io/2019/07/03/Others2/","excerpt":"","text":"转载出处 因为 shell 频繁 地使用文件名,shell 提供了特殊字符来帮助你快速指定一组文件名。这些特殊字符叫做通配符。 通配符 意义 * 匹配任意多个字符(包括零个或一个) ? 匹配任意一个字符(不包括零个) [characters] 匹配任意一个属于字符集中的字符 [!characters] 匹配任意一个不是字符集中的字符 [[:class:]] 匹配任意一个属于指定字符类中的字符 字符类 意义 [:alnum:] 匹配任意一个字母或数字 [:alpha:] 匹配任意一个字母 [:digit:] 匹配任意一个数字 [:lower:] 匹配任意一个小写字母 [:upper] 匹配任意一个大写字母 一些常用的匹配: 模式 匹配对象 * 所有文件 g* 文件名以“g”开头的文件 b*.txt 以”b” 开头,中间有零个或任意多个字符,并以”.txt” 结尾的文件 Data??? 以“Data”开头,其后紧接着 3 个字符的文件 [abc]* 文件名以”a”,”b”, 或”c” 开头的文件 BACKUP.[0-9][0-9][0-9] 以”BACKUP.” 开头,并紧接着 3 个数字的文件 [[:upper:]]* 以大写字母开头的文件 [[:digit:]]* 不以数字开头的文件 *[[:lower:]123] 文件名以小写字母结尾,或以“1”,“2”,或“3”结尾的文件","categories":[{"name":"Others","slug":"Others","permalink":"https://godway999.github.io/categories/Others/"}],"tags":[]},{"title":"数据库原理——第十一章:并发控制","slug":"Database11","date":"2019-06-17T11:21:04.000Z","updated":"2019-06-19T06:22:15.642Z","comments":true,"path":"2019/06/17/Database11/","link":"","permalink":"https://godway999.github.io/2019/06/17/Database11/","excerpt":"","text":"参考书目《数据库系统概论(第5版)》 并发控制概述 并发操作带来的不一致性: 丢失修改:T1和T2同时读入并修改,后者的提交覆盖了前者的提交 不可重复读:T1读取了数据A,期间T2修改了数据A,当T1再次读取A时发现与原先不一致 读“脏”数据:T1保存了对A的修改,但在T2读取A的期间,T1对A的操作被撤销导致A恢复原值,从而T2读取的是错误数据 并发控制的主要技术:封锁、时间戳、乐观控制法和多版本并发控制 封锁与封锁协议 封锁就是事务在对某数据对象操作之前先向系统发出请求,对其加锁 基本的封锁类型有: 排他锁又称写锁(简称X锁) 共享锁又称读锁(简称S锁) 封锁协议: 一级封锁协议:事务T在修改数据R之前必须先对其加X锁,直到事务结束才释放 一级封锁协议可防止丢失修改,并保证事务T是可恢复的,但其不保证可重复读和不读错误数据 二级封锁协议:在一级封锁协议基础上,增加事务T在读取数据R之前必须先对其加S锁,读完后即可释放S锁 二级封锁协议除防止了丢失修改,还进一步防止读错误数据,但其不保证可重复读 三级封锁协议:在一级封锁协议基础上,增加事务T在读取数据R之前必须先对其加S锁,直到事务结束释放S锁 三级封锁协议除防止了丢失修改,读读错误数据和不可重复读 活锁和死锁 活锁:就是操作系统中的饥饿,使用FCFS来预防活锁 死锁:就是操作系统中的死锁 死锁的预防: 一次封锁法:一次将所有要使用的数据全部加锁 顺序封锁法:先对数据对象规定一个封锁顺序,所有事务都按这个顺序实施封锁 操作系统中采用的预防死锁不适合数据库,因此数据库普遍采用诊断并解除死锁的方法,即允许发生死锁, 然后采用一定手段定期诊断系统中有无死锁, 若有则解除之 死锁的诊断方法: 超时法 等待图法 死锁的解除,通常采用的方法是:选择一个处理死锁代价最小的事务,将其撤销,释放此事务持有的所有锁,使其他事务得以继续运行下去 并发调度的可串行性 可串行化调度:多个事务的并发执行是正确的,当且仅当其结果与按某一次序串行执行这些事务时的结果相同 可串行性是并发事务正确调度的准则。即一个给定的并发调度,当且仅当它是可串行化的,才认为是正确调度 若一个调度是冲突可串行化,则一定是可串行化调度 两段锁协议 数据库系统采用两段锁协议(2PL)的方法实现并发调度的可串行性,从而保证调度的正确性 两段锁协议是指所有事务必须分两个阶段对数据项加锁和解锁: 扩展阶段(第一阶段):获得封锁。在对任何数据进行读、写操作之前,首先要申请并获得对该数据的封锁;此阶段,可以申请获得任何数据项上任何类型的锁,但是不能释放锁 收缩阶段(第二阶段):释放封锁。在释放一个封锁之后,事务不再申请和获得任何其他封锁 事务遵守两段锁协议是可串行化调度的充分条件 一次封锁法遵守两段锁协议,但两段锁协议并不要求事务必须一次将所有要使用的数据全部加锁,因此遵守两段锁协议的事务仍可能发生死锁","categories":[{"name":"数据库原理","slug":"数据库原理","permalink":"https://godway999.github.io/categories/数据库原理/"}],"tags":[]},{"title":"数据库原理——第十章:数据库恢复技术","slug":"Database10","date":"2019-06-17T11:21:01.000Z","updated":"2019-06-19T03:22:56.512Z","comments":true,"path":"2019/06/17/Database10/","link":"","permalink":"https://godway999.github.io/2019/06/17/Database10/","excerpt":"","text":"参考书目《数据库系统概论(第5版)》 事务的基本概念 事务是用户定义的一个数据库操作序列,这些操作要么全做,要么全不做,是一个不可分割的工作单位 COMMIT操作,即提交,是将事务中所有对数据库的更新写回到磁盘上的物理数据库中 ROLLBACK操作,即回滚,事务运行过程中发生了错误,系统将事务对数据库所有已完成的操作全部撤销,回滚到事务开始时的状态 事务的ACID特性: 原子性(Atomicity):事务是数据库的逻辑工作单位,事务中包括的诸操作要么都做,要么都不做 一致性(Consistency):事务执行的结果必须是使数据库从一个一致状态变到另一个一致状态;一致性与原子性是密切相关的 隔离性(Isolation):一个事务的执行不能被其他事务干扰 持续性(Durability):也称为永久性,一个事务一旦提交,他对数据库中的数据改变就应该是永久性的 ACID可能遭到破坏的因素有: 多个事务并发运行时,不同事务的操作交叉执行 事务在运行过程中被强行停止 数据库恢复:数据库管理系统把数据库错误状态恢复到某一已知的正确状态(亦称为一致状态) 故障的种类 事务内部的故障 事务内部的故障指事务执行到某一位置主动选择回滚。例如银行执行扣款时,若余额小于0,则主动执行回滚,回到未扣款前的状态 系统故障 系统故障指造成系统停止运转的任何事件,使得系统要重新启动 回复子系统在系统重启后,需要撤销所有未完成的事务,重做所有已提交的事务,以将数据库恢复到一致状态 介质故障 指外存故障,如磁盘损坏、瞬时强磁场干扰、火灾等,破坏性最大 计算机病毒 各类故障对数据库的影响有两种结果: 数据库本身被破坏 数据库未被破坏,但数据可能不正确,这是由于事务的运行被非正常终止造成的 恢复的实现技术 恢复的基本原理——冗余,常用技术有数据转储和登记日志文件 数据转储(backup) 转储:即数据库管理员定期地将整个数据库复制到其他存储介质上保存起来地过程,备用数据称为后备副本 转储操作十分耗费时间和资源,不能频繁进行 转储可分为两种状态:静态转储和动态转储 静态转储:在系统中无运行事务时进行的转储操作,转储期间不允许对数据库执行任何存取和修改 得到的是一个一致性副本 降低数据库的可用性 动态转储:转储期间允许对数据库进行存取和修改,即转储和用户事务可以并发执行 必须把转储期间各事务对数据库的修改活动记录下来,建立日志文件 转储还可分为两种方式:海量转储和增量转储 海量转储:每次转储全部数据库 增量转储:每次只转储上一次转储后更新过的数据 转储方法:动态海量转储、动态增量转储、静态海量转储、静态增量转储 登记日志文件(logging) 日志文件是用来记录事务对数据库地更新操作的文件 日志文件有两种格式:以记录为单位的日志文件和以数据块为单位的日志文件 对于以记录为单位的日志文件,其需要登记的内容包括: 各个事务的开始标记 各个事务的结束标记 各个事务的所有更新操作 日志文件的作用: 事务故障恢复和系统故障恢复必须用日志文件 在动态转储方式中必须建立日志文件,后备副本和日志文件结合起来才能有效的恢复数据库 在静态转储中也可以建立日志文件,用于加速数据库恢复过程 为保证数据库是可恢复的,登记日志文件的两条原则: 登记的次序严格按并发事务执行的时间次序 必须先写日志文件,后写数据库 恢复策略 事务故障的恢复 事务故障是指在运行至正常终止点前被终止,此时恢复子系统利用日志文件撤销(UNDO)此事务已对数据库进行的修改 事务故障的恢复由系统自动完成,对用户是透明的 恢复步骤为: 反向扫描日志文件,查找该事务的更新操作 对该事务的更新操作执行逆操作 继续反向扫描日志文件,查找该事务的其他更新操作,并做同样处理 如此处理下去,直到读到此事务的开始标记,事务故障恢复完成 系统故障的恢复 系统故障导致不一致的原因有两个: 未完成事务对数据库的更新已写入数据库 已提交事务对数据库的更新可能还停留在缓冲区没来得及写入数据库 恢复操作就是撤销故障发生时未完成的事务和重做已完成的事务 系统故障的恢复由系统在重新启动时自动完成,不需要用户的干预 恢复步骤为: 正向扫描日志文件,找出在故障发生前已经提交的事务,将其事务标识记入重做队列(REDO-LIST)。同时找出故障发生时尚未完成的事务,将其事务标识记入撤销队列(UNDO-LIST) 对撤销队列中的各个事务进行撤销(UNDO)处理 对重做队列中的各个事务进行重做(REDO)处理 介质故障的恢复 发生介质故障后,磁盘上的物理数据和日志文件被破坏,这是最严重的故障,恢复方法是重装数据库,然后重做已完成的事务 介质故障的恢复需要数据库管理员介入 恢复步骤为: 装入最新的数据库副本 装入相应的日志文件副本,重做已完成的事务 具有检查点的恢复技术 检查点记录的内容包括: 建立检查点时刻所有正在执行的事务清单 这些事务最近一个日志记录的地址 重新开始文件用来记录各个检查点记录在日志文件中的地址 动态维护日志文件的方法是,周期性地执行建立检查点、保存数据库状态的操作,具体步骤为: 将当前日志缓冲区中的所有日志记录写入磁盘的日志文件上 在日志文件中写入一个检查点记录 将当前数据缓冲区的所有数据记录写入磁盘的数据库中 把检查点记录在日志文件中的地址写入一个重新开始文件 简化为:保存日志 -> 生成检查点 -> 保存数据提交到数据库 -> 将检查点写入重新开始文件 使用检查点方法可以改善恢复效率 系统使用检查点方法进行恢复的步骤: 从重新开始文件中找到最后一个检查点记录在日志文件中的地址,利用该地址找到日志文件中最后一个检查点记录 由该检查点记录得到检查点建立时刻所有正在执行的事务清单,并将其做为UNDO-LIST。另外新建一个空的REDO-LIST 从检查点开始正向扫描日志文件 如有新开始的事务T,将T加入UNDO-LIST 如有提交的事务J,将J从UNDO-LIST移入REDO-LIST 对UNDO-LIST中的每个事务执行撤销操作;对REDO-LIST中的每个事务执行重做操作","categories":[{"name":"数据库原理","slug":"数据库原理","permalink":"https://godway999.github.io/categories/数据库原理/"}],"tags":[]},{"title":"数据库原理——第九章:关系查询处理和查询优化","slug":"Database9","date":"2019-06-17T11:20:34.000Z","updated":"2019-06-19T04:13:23.118Z","comments":true,"path":"2019/06/17/Database9/","link":"","permalink":"https://godway999.github.io/2019/06/17/Database9/","excerpt":"","text":"参考书目《数据库系统概论(第5版)》 关系数据库系统的查询处理 关系数据库管理系统查询处理分为4个阶段:查询分析、查询检查、查询优化和查询执行 查询分析:对SQL语句进行语法分析和词法分析,报告语句中可能的语法错误 查询检查:对合法的查询语句进行语义检查,即根据数据字典中有关的模式定义检查语句中的数据库对象,如关系名、属性名是否存在和合法 可能涉及视图消解、用户存取权限和完整性约束检查,这时的完整性检查是初步的、静态的检查 关系数据库管理系统一般都用查询树(也即语法分析树)来表示扩展的关系代数表达式 查询优化:选择一个高效执行的查询处理策略;按照优化的层次一般可分为代数优化和物理优化 代数优化是指关系代数表达式的优化 物理优化是指存取路径和底层操作算法的选择 查询执行:依据优化器得到的执行策略生成查询执行计划,由代码生成器生成执行这个查询计划的代码。然后执行并回送查询结果 关系数据库系统的查询优化 查询优化在关系数据库系统中有着非常重要的地位,关系数据库系统取得巨大成功的原因关键是得益于查询优化技术的发展 查询优化的优点不仅在于用户不必考虑如何最好地表达查询以获得较高的效率,而且在于系统可以比用户程序做的更好,原因如下: 优化器可以从数据字典中获取许多统计信息,而用户程序则难以获得这些信息 如果数据库的物理统计信息变了,系统可以自动对查询进行重新优化而不必重写程序 优化器可以考虑数百种不同的执行方案,而程序员一般只能考虑有限的几种 优化器中实现包含了很多复杂的优化技术,这些技术的实现降低了编写人员的门槛 在集中式数据库中,查询执行开销主要包括磁盘存取块数(I/O代价)、处理机时间(CPU代价)以及查询的内存开销,在分布式数据库中还要加上通信代价 查询执行的总代价 = I/O代价 + CPU代价 + 内存代价 + (通信代价) 代数优化 查询树的启发式优化: 选择运算应尽可能先做 把投影运算和选择运算同时进行 把投影同其前或后的双目运算结合起来 把某些选择同它前面要执行的笛卡尔积结合起来成为一个连接运算 找出公共子表达式 物理优化 物理优化的目的是为了选择高效合理的操作算法或存取路径,方法有 基于规则的启发式优化 基于代价估算的优化 二者结合的优化方法","categories":[{"name":"数据库原理","slug":"数据库原理","permalink":"https://godway999.github.io/categories/数据库原理/"}],"tags":[]},{"title":"计算机网络——第七章:无线网络和移动网络","slug":"Network7","date":"2019-06-16T03:53:59.000Z","updated":"2019-07-14T01:39:30.290Z","comments":true,"path":"2019/06/16/Network7/","link":"","permalink":"https://godway999.github.io/2019/06/16/Network7/","excerpt":"","text":"参考书目《计算机网络:自顶向下方法(第七版)》 概述 无线网络分类: 单跳,基于基础设施。如802.11网络和4G LTE 单跳,无基础设施。如蓝牙网络和自组织模式的802.11网络 多跳,基于基础设施。如耨鞋无线传感网络和无线网状网络 多跳,无基础设施。如移动自组织网络(mobile ad hoc network, MANET)和车载自组织网络(vehicular ad hoc network, VANET) 无线链路和网络特征 有线链路和无线链路的区别: 递减的信号强度。如电磁波在穿过物体时强度将衰减 来自其它源的干扰。来自环境和其他发送源的干扰 多径传播。电磁波的一部分受物体和地面的反射,到达接收方时走了不同长度的路径,则会出现多径传播,会导致接收方收到的信号变得模糊 较大的信噪比(SNR)使接收方更容易从背景噪声中提取传输信号;比特差错率(BER)表示接收方收到的有错传输比特的概率 物理层的特征: 对于给定的调制方案,SNR越高,BER越低 对于给定的eSNR,具有较高比特传输率的调制技术(无论差错与否)将具有较高的BER 物理层调制技术的动态选择能用于适配对信道条件的调制技术 CDMA 在CDMA协议中,要发送的每个比特都通过乘以一个信号(编码)的比特来进行编码,这个信号的变化速率(通常称为码片速率)比初始数据比特序列的变化速率要快得多 选择CDMA编码的关键是:使所有节点的CDMA编码所表示的代数向量彼此之间相互垂直 WiFi:802.11 无线LAN 802.11 体系结构 802.11 体系结构的基本构件模块是基本服务集(Basic Service Set, BSS),一个BSS包括一个或多个无线站点和一个接入点(Access Point, AP)的中央基站 802.11规定: 每个无线站点若要发送或接收数据,必须先与一个AP相关联;在环境中有多个AP时,仅有关联的AP才会向你的无线站点发送数据 每个AP会被分配到一个服务集标识(Service Set Identifier, SSID) 802.11定义了11个部分重叠的信道,特别是1、6和11是唯一的3个非重叠信道 每个AP必须周期性地发送信标帧,每个信标帧包含该AP的SSID和MAC地址 扫描信道和监听信标帧的过程被称为被动扫描;无线主机也能够通过广播探测帧执行主动扫描,但对于主动扫描需要二次请求/响应握手 802.11 MAC协议 802.11 MAC协议使用带碰撞避免的CSMA(CSMA/CA),并且由于无线信道相对较高的比特粗误码率,使用链路层确认/重传(ARQ)方案 802.11 MAC协议未实现碰撞检测的原因? 检测碰撞的能力要求站点具有同时发送和接收的能力,由于接收信号的强度通常远远小于发送强度,制造这种硬件的代价较大。 即使能做到,也会因为信号衰减和终端隐藏问题,而无法检测到所有碰撞 链路层确认方案的过程: 目的站点收到一个通过CRC校验的帧后,他等待一个被称为短帧间间隔(Short Inter-Frame Spacing, SIFS)的一小段时间,然后发挥一个确认帧 若发送站点在给定时间内未收到确认帧,则使用CSMA/CA协议重传该帧 若在固定次重传之后仍未收到确认,则发送站点放弃发送并丢弃该帧 CSMA/CA协议过程: 如果某站点最初监听到信道空闲,它将在一个被称作分布式帧间间隔(Distributed Inter-Frame Spacing, DIFS)的短时间段后发送该帧 否则该站点选取一个随机回退值(像CSMA/CD那样)并且在侦听信道空闲时递减该值。当侦听到信道忙时,计数值保持不变 当计数值减为0时(注意到这只可能发生在信道被侦听为空闲时),该站点发送整个数据帧并等待确认 如果收到确认,发送站点知道它的帧已经被目的站点正确接收。如果该站点要发送另一帧,它将从第2步开始CSMA/CA协议。如果未收到确认,发送站点将重新进入第2步中的回退阶段 802.11的目标是无论如何尽可能避免碰撞 处理隐藏终端:RTS和CTS 站点使用短请求发送(Request to Send, RTS)控制帧和短允许发送(Clear to Send, CTS)控制帧来预约对信道的访问。过程如下: 当发送方要发送一个DATA帧时,他首先等待一个DIFS,然后向AP发送一个RTS帧,指示传输DATA帧和确认(ACK)帧需要的总时间 当AP收到RTS帧后,等待一个SIFS,之后它广播一个CTS帧作为响应。该CTS有两个目的:给发送方明确发送许可,也指示其他站点在预约期内不要发送 发送方收到CTS后,在等待一个SIFS之后发送DATA 接收方在完全接收DATA数据之后,等待一个SIFS后,广播一个ACK帧,传递预约结束的消息 使用RTS和CTS能够在两个重要方面提高性能: 终端隐藏问题被缓解了,因为长的DATA帧只有在预约过后才会发送 因为RTS和CTS帧较短,涉及RTS和CTS帧的碰撞将仅持续短RTS和CTS帧的持续时间 IEEE 802.11 帧结构 892.11帧中最引人注的的是他有4个MAC地址字段 地址1是接收该帧的无线站点的MAC地址 地址2是传输该帧的站点的MAC地址 地址3是当前BSS中的AP的第一跳路由器接口的MAC地址(地址3允许AP在构建以太网帧时能够确定目的MAC地址),所以其在BSS和在有线局域网互联中起着关键的作用 地址4当AP在自组织模式中互相转发时使用 移动管理 间接路由 直接路由 间接路由存在三角路由选择问题。直接路由克服了这个低效的问题,但却是以增加复杂性为代价。 移动IP 问题与思考 无线网络中高出错率是怎样影响效率的? 拥塞控制的问题主要集中在效率和公平性 改进 TCP 的两个重要原则就是: (1) 让发送端清楚网络的真实状态 (2) 采用跨层设计的思想,让 IP 层、逻辑链路层和 MAC 层都恰当地参与问题发现和问题解决过程,缩短控制周期","categories":[{"name":"计算机网络","slug":"计算机网络","permalink":"https://godway999.github.io/categories/计算机网络/"}],"tags":[]},{"title":"计算机网络——第六章:链路层和局域网","slug":"Network6","date":"2019-06-14T06:53:09.000Z","updated":"2019-07-02T15:49:25.410Z","comments":true,"path":"2019/06/14/Network6/","link":"","permalink":"https://godway999.github.io/2019/06/14/Network6/","excerpt":"","text":"参考书目《计算机网络:自顶向下方法(第七版)》 链路层概述 链路层提供的服务: 成帧 将网络层数据报封装成链路层帧。一个帧由一个数据字段和若干首部字段组成 链路接入 媒体访问控制(Medium Access Control, MAC)协议规定了帧在链路上的传输的规则。 对于点对点链路(PPP)MAC协议比较简单,当链路空闲时发送方都能发送;对于广播链路,即所谓的多路访问问题,MAC协议用于协调多个节点的帧传输 可靠交付 链路层可靠交付服务通常用于易于产生高差错率的链路,如无线链路,其目的是本地纠正一个差错,而不是通过运输层或应用层协议迫使进行端到端的数据重传 对于低比特差错的链路,链路层可靠交付服务可能会认为是一种不必要的开销,因此许多有线的链路层协议不提供可靠交付服务 差错检测和纠正 链路层的差错检测通常更复杂,并且用硬件实现 差错纠正使得接收方检测出帧中出现的比特差错,而且能定位并纠正它们 链路层的主体部分是在*网络适配器(network adapter)中实现的,网络适配器有时也被称为网卡(Network Interface Card, NIC) 差错检测和纠正技术 使用差错检测和纠正技术仍有可能有未检出比特差错,因而需要选择一个方案使得这种事情的发生概率很小 传输数据中检测差错的三种技术:奇偶校验、检验和方法(更多用于传输层)、循环冗余检测(通常用于适配器中的链路层) 奇偶校验 单比特奇偶校验只能用于单比特差错检测,而实际中经常以聚集地方式出现 二维奇偶检验可以检测到单比特差错并且定位纠正错误比特,但对于多比特差错则只能检测而不能纠正 接收方检测和纠正差错的能力被称为前向纠错 通过请求发送方重传出错的数据称为后向纠错 检验和方法 因特网检验和(checksum)就基于这种方法,以16比特为单位求取检验和 为什么运输层使用检验和而链路层使用CRC? 传输层差错检测用软件实现,简单而快速如检验和这样的方案是重要的 链路层差错检测在适配器中有专用硬件,能够快速执行更复杂的CRC操作 循环冗余检测 循环冗余检测编码(CRC)也称为多项式编码 CRC前提:对于\\(d\\)比特的数据\\(D\\),发送方和接收方事先协商一个\\(r+1\\)比特的\\(G\\)(称为生成多项式(generator)),并且要求\\(G\\)的最高位为1 CRC核心思想:对于一个给定的\\(D\\),发送方要选择\\(r\\)个附加比特R将其附加到D后面,使得得到的长为\\(d+r\\)的比特模式用模2算术恰好能被\\(G\\)整除 CRC检测过程:接收用G去除接收到的\\(d+r\\)比特,如果余数不为0,则说明出现了差错 \\(R\\)的计算方法: \\[R = (D * 2^r) \\% G\\] CRC能检测小于\\(r+1\\)比特的突发差错,这意味着所有连续的\\(r\\)比特或者更少的差错都可以检测到 多路访问链路和协议 点对点链路的链路层协议有:PPP(点对点)协议和HDLC(高级数据链路控制)协议 对于广播链路需要使用多路访问协议,可划分为三种类型:信道划分协议、随机接入协议、轮流协议 信道划分协议 常见的有三种:时分多路复用TDM、码分多路复用FDM、码分多址CDMA TDM和FDM的优点:它避免了碰撞,并在N个节点之间公平的划分了带宽;缺点:现在一个节点只能使用R/N的带宽,从而链路利用效率不高 CDMA为每个节点分配一种不同的编码,然后每个节点用它唯一的编码来对它发送的数据进行编码。CDMA的特性在于不同节点能够同时传输,并且他们各自相应的接收方仍能正确接收 CDMA例子 随机接入协议 在随机接入协议中,每个传输节点总是以信道的全部速率进行发送。当有碰撞时,每个节点等待一个随机时延后再次重发该帧,直到该帧无碰撞的通过为止 常用的有ALOHA协议和载波侦听多路访问协议(CSMA) 时隙ALOHA需要节点之间同步时钟,其的最大效率为\\(\\frac{1}{e} \\approx 0.37\\) 纯ALOHA不需要节点间的同步,其最大效率为\\(\\frac{1}{2e} \\approx 0.18\\) 在CSMA中,广播信道的端到端信道传播时延(信号从一个节点传播到另一个节点的时间),决定了最小帧长和线缆长度,因为该时延越长,一个待发送节点不能侦听到另一个已经开始传输的节点的概率越大 CSMA/CD运行流程: 适配器从网络获得一条数据报,准备链路层帧,并将其放入帧适配器缓存中 如果适配器侦听到信道空闲(侦听96比特时间表示空闲,同时也是为了保证帧间最小间隔,目的为了使刚刚收到数据帧的站可及时处理完接收缓存),它开始传输帧。若适配器侦听到信道正在忙,它将等待直到它判断信道空闲时才传输帧 在传输的过程中,适配器监视是否其他节点也在使用广播信道 若整个传输过程中都没有监测到其他适配器的信号能量,则代表该帧传输完成。若检测到来自其他适配器的信号能量,它在传输完强化冲突帧(32或48比特时间)之后中止传输,传输强化冲突帧是让为了确保所有用户都知道发生了碰撞 中止传输后,适配器等待一个随机时间量,然后返回步骤2 CSMA/CD使用二进制指数后退算法来决定碰撞后等待的随机时间量。假设传输一个给定帧,该帧经历了\\(n\\)次碰撞,节点随机的从\\(\\{ 0, 1, ... , 2^n-1 \\}\\)中选取一个\\(K\\)值,则该节点的等待的实际时间量为\\(K \\bullet 512\\),可看到\\(K\\)的可选集合长度随着碰撞次数呈指数增长,从而节点间再次碰撞的概率越小 CSMA/CD效率定义为:*当有大量的活跃节点,且每个节点有大量的帧要发送时,帧在信道中无碰撞地传输的那部分时间在长期运行时间中所占的份额。令\\(d_{prop}\\)表示信号能量在任意两个适配器之间传播所需的最大时间,\\(d_{trans}\\)表示传输一个最大长度的以太网帧的时间 \\[效率 = \\frac{1}{1 + 5d_{prop}/d_{trans}}\\] 轮流协议 轮询协议:节点之一被指定为主节点,主节点以循环的方式轮询(poll)每个节点(问XX节点:“你现在要发送帧吗?”) 令牌传递协议:没有主节点,一个称为令牌(token)的小的特殊帧在节点间以某种固定的次序进行交换,拥有令牌的节点才能发送帧 交换局域网 适配器的MAC地址具有扁平结构,并且不论适配器到哪里都还不会发生变化 IP地址具有层次结构(即分为网络号和主机号),当主机移动时,主机的IP地址需要改变,即改变它所连接到的网络 主机和路由器接口除了网络层地址之外还有MAC地址的原因 局域网是为任意网络层协议而设计的,而不只是用于IP和因特网,使用MAC地址,可以保持兼容性 如果适配器使用网络层地址不使用MAC地址的话,网络层地址必须存储在适配器的RAM中,每次适配器移动(或上电)时要重新配置 ARP协议 地址解析协议(Address Resolution Protocol, ARP),实现IP地址到MAC地址之间的转换 每台主机或路由器在其内存中具有一个ARP表,这张表包含IP地址到MAC地址的映射关系,其中TTL指示了从表中删除每个映射的时间。举例如下 IP地址 MAC地址 TTL 222.222.222.221 88-B2-2F-54-1A-0F 13:45:00 关于ARP 查询ARP报文是在广播帧中发送的,而响应ARP在一个标准帧中发送 ARP是即插即用的,也就是说ARP表是自动建立的,即它不需要系统管理员来配置 以太网帧结构 数据字段(46~1500字节);这个字段承载了IP数据报。以太网的最大传输单元MTU是1500字节,数据字段的最小长度是46字节(如果IP数据报小于46字节则必须被填充到46字节) 目的地址(6字节);包含目的适配器的MAC地址 源地址(6字节);包含传输该帧到局域网上的适配器的MAC地址 类型字段(2字节);类型字段允许以太网复用多种网络协议。适配器根据该字段选择将数据字段的内容传递给哪个网络层协议。该字段和网络层中数据报中的协议字段、运输层报文段中的端口号相类似,都是为了把一层中的某协议与上一层的某协议结合起来 CRC(4字节);用于CRC循环冗余检测 前同步码(8字节);以太网帧以一个8字节的前同步码字段开始,该字段前7个字节用于“唤醒”接受适配器,并将它们的时钟和发送方的时钟同步 所有的以太网技术都向网络层提供无连接服务:发送帧前没有握手的过程 以太网技术都向网络层提供不可靠服务:当适配器收到一个帧时,不论是否通过CRC校验,该适配器并不回复发送方它是否正确收到,因此发送方根本不知道它发送的帧是否到达了接收方并通过了CRC校验 以太网技术 以太网从10M到10G是如何发展的? 在100mbs的以太网中,采用的是保持最短帧长不变,但将一个网段的最大电缆长度减小到100m,帧时间间隔从原来的9.6us改为现在的0.96us。 吉比特以太网,仍保持一个网段最大长度为100m,但采用“载波延伸”技术,使得最小帧仍为64字节(保持兼容性),如果数据帧不超过512字节,则在FCS域后面添加“载波延伸”域。为了避免载波延伸延伸浪费,又使用了“分组突发”技术。当很多短帧要发送时,第一个短帧采用“载波延伸”方法进行填充,后面的一些短帧可以一个接一个发送,它们之间只要留必要的帧间最小间隔即可。这样就形成一串分组突发,直到达到1500字节或稍多一些为止。从而提高链路的利用率。 10吉比特网仍保持标准规定的以太网最小最大帧长,为了保持兼容。由于数据率很高,吉比特以太网不再使用铜线而只使用光纤作为传输媒体。减小时间间隔。 以太网帧结构从始至终一直保持不变 现代交换机是全双工的,这使得一台交换机和一个节点能够同时向对方发送帧而没有干扰。也就是说,在基于交换机的以太局域网中,没有碰撞,因此可以没必要再使用MAC协议 链路层交换机 交换机的任务是接收入链路层帧并将它们转发到出链路,并且交换机对于子网中的主机和路由器是透明的 交换机转发和过滤 过滤:决定一个帧应该转发到某个接口还是应当将其丢弃 转发:决定一个帧应该被导向哪个接口,并把该帧移动到那些接口 交换机的优点 消除碰撞,没有因碰撞而浪费的带宽 异质的链路,局域网中的不同链路能够以不同的速率(如100Mbps和1Gbps)并且能够在不同的媒体(如铜线和光纤)上运行 管理,易于进行网络管理 自学习的,是即插即用设备 交换机和路由器比较 都是存储转发的设备 路由器维持一个路由表,使用路由算法 交换机维持一个交换表,使用过滤、自学习算法 交换机是即插即用的,而路由器需要管理人员的配置 优化路由,路由器有,交换机无 交换机的活跃拓扑限制为一棵生成树。而路由器则没有生成树限制从而可以产生多条活跃链路 路由器提供了更健壮的流量隔离方式和对广播风暴的控制,而交换机对广播风暴不提供任何保护 虚拟局域网 传统局域网的3个缺点 缺乏流量隔离 交换机的无效使用 管理用户 支持虚拟局域网(VLAN)的交换机允许一个单一的物理局域网基础设施定义多个虚拟局域网 在一个基于端口的VLAN中,交换机的接口由网络管理员划分为组,每个组构成一个VLAN,在每个VLAN中的接口形成一个广播域 链路虚拟化:网络作为链路层 多协议标签交换(MPLS)和VPN 问题与思考 差分曼切斯特编码比曼切斯特编码的变化要少,因此更适合与传输高速的信息,被广泛用于宽带高速网中。但这两种编码的效率仅可达到50%左右,因为频率增加了一倍但传输的信息量却没有增加 冲突域是如何决定最小帧长的? 发送的帧的最短长度应当保证在发送完毕之前,必须能够检测到可能最晚来到的冲突信号,故而帧发送时间应该大于2倍的信道传播时延","categories":[{"name":"计算机网络","slug":"计算机网络","permalink":"https://godway999.github.io/categories/计算机网络/"}],"tags":[]},{"title":"计算机网络——第五章:网络层(控制平面)","slug":"Network5","date":"2019-06-13T12:08:11.000Z","updated":"2019-06-17T11:52:02.074Z","comments":true,"path":"2019/06/13/Network5/","link":"","permalink":"https://godway999.github.io/2019/06/13/Network5/","excerpt":"","text":"参考书目《计算机网络:自顶向下方法(第七版)》 路由选择算法 路由选择算法的目的是从发送方到接收方的过程确定一条好的路由路径。通常,一条好的路由路径指具有最低开销的路径 如下为计算机网络经典图模型 路由选择算法的一种分类方式是根据集中还是分散来划分: 集中式路由选择算法:用完整的、全局性的网络知识计算出从源到目的地之间的最低开销路径。具有全局状态信息的算法被称作链路状态算法(Link State, LS) 分散式路由选择算法:路由器以迭代、分布式的方式计算出最低开销路径。这种分散式路由选择算法称为距离向量算法DV(Distance Vector, DV) LS路由选择算法 在LS中,网络拓扑和所有的链路开销都是已知的,实践中这是通过让每个节点向网络中所有其他节点广播链路状态分组来完成的,其中每个链路状态分组包含它所连接的链路的标识和开销 节点广播的结果是所有节点都具有该网络的统一、完整的视图,于是每个节点都能够像其他节点一样,运行LS算法并计算出相同的最低开销路径集合 书上介绍了Dijkstra最短路径算法,此处不再赘述 LS算法存在的潜在问题————振荡。这是由于消息传播的时延导致的,它不仅存在于LS算法中,也存在于任何使用拥塞或基于时延的链路测度的算法 DV路由选择算法 距离向量算法是一种迭代的、异步的和分布式的算法 分布式的:因为每个节点都要从一个或多个直接相连的邻居接收某些信息,执行计算,然后将其结算结果分发给邻居 迭代的:因为此过程一直要持续到邻居之间无更多信息交互为止(有趣的是,此算法是自我终止的) 异步的:因为它不要求所有节点相互之间步伐一致地操作 DV算法的核心思想基于贝尔曼-弗洛伊德方程 \\[d_x(y) = min_v{c(x, v) + d_v(y)}\\] 其中\\(d_x(y)\\)表示从节点x到节点y的最低开销路径的开销,\\(c(x, v)\\)表示从节点x到节点v的开销,该算法思想一句话总结就是:从x到y的距离能否通过途径v节点而变小 DV算法存在的问题:路由选择环路,导致关于链路开销增加的坏消息传播的很慢! LS与DV的比较 报文复杂性 LS要求每个节点都知道网络中每条链路的开销,这就需要发送 O(|N||E|) 个报文,且任何一条链路的开销改变都需要在全网广播 DV要求在每次迭代时,在两个直接相连节点间交换报文。当链路开销改变时,DV仅当新的链路开销导致与该链路相连节点的最低开销路径发生改变时,才传播已改变的链路开销 收敛速度 LS是一个O(|N|^2)算法 DV算法收敛较慢,且会遇到路由选择环路和无穷计数问题 健壮性 在LS算法下,路由计算在某种程度上是分离的,这提供了一定程度的健壮性 DV算法中一个不正确的节点计算值会扩散到整个网络 总之,两个算法没有一个是明显的赢家,它们的确都在因特网中得到了应用 自治系统内部的路由选择:OSPF 为什么要划分自治系统(Autonomous Systerm, AS)? 规模。必须采取一些措施以减少像因特网这种大型网络中的路由计算的复杂度 管理自治。ISP通常希望按自己的意愿运行路由器,如在自己的网络中运行它所选的路由选择算法,或对外部隐藏其网络的内部组织面貌 每个AS通常由一组处在相同管理控制下的路由器组成,ISP可在其整个网络使用一个AS或将其拆分为多个AS 每个AS有一个唯一的AS号(ASN),AS号由ICANN组织分配 开放最短路优先OSPF(Open Shortest Path First) OSPF是一种链路状态协议,它使用洪泛链路状态信息和Dijkstra算法。 OSPF的优点: 安全 能够鉴别OSPF路由器之间的交换,仅有受信任的路由器能参与AS内的OSPF协议,因此可防止恶意入侵者将不正确的信息注入路由表内 多条相同开销的路径 当到达某目的地的多条路径具有相同的开销时,OSPF允许使用多条路径(无须仅选择单一的路径来承载所有的流量) 对单播与多播路由选择的综合支持 多播OSPF(MOSPF)[RFC 1584]提供对OSPF的简单拓展,以便提供多播路由选择 支持在单个AS中的层次结构 一个OSPF自治系统能够层次化地配置多个区域,在每个区域一台或多台区域边界路由器负责为流向该区域以外的分组提供路由选择。最后,在AS内只有一个OSPF区域配置为主干区域,其作用是为该AS中的其他区域之间的流量提供路由选择。 整个过程为分组先到区域边界路由器,经过主干区域到达目的区域的边界路由器,最后到达目的地 ISP之间的路由选择:BGP 在因特网中,所有的AS运行相同的AS间路由选择协议,称为边界网关协议(Border Gateway Protocol, BGP) 在BGP中,分组并不是路由到一个特定的目的地址,相反是路由到CIDR化的前缀,其中每个前缀表示一个子网或子网的集合(如138.16.68/22) 在BGP中,每对路由器通过使用179端口的半永久TCP连接交换路由选择信息 每条直接连接以及所有通过该链接发送的BGP报文称为BGP连接。此外,跨越两个AS的BGP连接称为外部BGP(eBGP)连接,在相同AS中的两台路由器之间的BGP会话称为内部BGP(iBGP)连接 在BGP前缀中的BGP属性中,AS-PATH和NEXT-HOP属性比较重要 AS-PATH属性包含了通告已经通过的AS的列表(使用ASN标识,如AS1 AS2 ...),BGP还使用该属性来检测和防止通告环路(若路由器在路径列表看到自己的AS,它将拒绝该通告) NEXT-HOP是AS-PATH起始的路由器接口的IP地址(即该路径的源的IP地址) BGP还常被用于实现IP任播(anycast)服务,该服务被DNS系统广泛用于将DNS请求指向最近的根DNS服务器 SDN:软件定义网络(Software-Defined Networking) SDN体系结构的4个关键特征: 基于流的转发 SDN控制的交换机的分组转发工作,能够基于运输层、网络层或链路层首部中任意数量的首部字段值进行(传统方法中的IP数据报的转发仅依据数据报的目的IP地址进行) 数据平面与控制平面分离 数据平面由网络交换机组成;控制平面由服务器以及决定和管理交换机流表的软件组成 网路控制功能:位于数据平面交换机外部 控制平面自身由两个组件组成:SDN控制器(或网络操作系统)以及若干网络控制应用程序 可编程的网络 通过运行在控制平面中的网络控制应用程序,该网络是可编程的","categories":[{"name":"计算机网络","slug":"计算机网络","permalink":"https://godway999.github.io/categories/计算机网络/"}],"tags":[]},{"title":"数据库原理——第八章:数据库编程","slug":"Database8","date":"2019-05-22T01:19:29.000Z","updated":"2019-06-18T05:29:16.188Z","comments":true,"path":"2019/05/22/Database8/","link":"","permalink":"https://godway999.github.io/2019/05/22/Database8/","excerpt":"","text":"参考书目《数据库系统概论(第5版)》 嵌入式SQL 嵌入式SQL是将SQL语句嵌入程序设计语言中,被嵌入的语言如C、C++、Java等称为宿主语言,简称主语言 SQL语言负责操纵数据库,高级程序语言负责控制逻辑流程 数据库工作单元和源程序工作单元之间的通信主要包括: 向主语言传递SQL语句的执行信息,使主语言能够据此信息控制程序流程,主要用SQL通信区实现 主语言向SQL语句提供参数,主要用主变量实现(SQL语句中使用的主语言程序变量简称主变量) 将SQL语句查询数据库的结果交主语言处理,主要用*主变量和游标实现 游标:游标是系统为用户开设的一个数据缓冲区,存放SQL语句的执行结果。游标类似于数据缓冲区内的指针,用户可以通过游标逐一获取缓冲区内的数据 过程化SQL 过程化SQL(Procedural Language/SQL, PL/SQL),其基本结构是块 定义方式 123456DECLARE 变量、常量、游标、异常等BEGIN SQL语句、过程化SQL的流程控制语句EXCEPTION 异常处理部分END; 流程控制 IF语句 123IF condition THEN Sequence_of_statements;END IF; IF-THEN语句 12345IF condition THEN Sequence_of_statements1;ELSE Sequence_of_statements2;END IF; LOOP语句 123LOOP Sequence_of_statements;END LOOP; WHILE-LOOP语句 123WHILE condition LOOP Sequence_of_statements;END LOOP; FOR-LOOP语句 123FOR count IN [REVERSE] bound1 .. bound2 LOOP Sequence_of_statements;END LOOP; 存储过程和函数 过程化SQL块分为两种:命名块和匿名块 匿名块:每次执行时都要进行编译,它不能被存储到数据库中,也不能在其他过程化SQL块中调用 命名块:过程和函数是命名块,它们被编译后保存在数据库中,称为持久性存储模块(Persistent Stored Module, PSM),可以被反复调用,运行速度较快 ------后续语句实现基于MySQL------ 存储过程 使用SQL语句书写,经过编译和优化后存储在数据库中,因此称为存储过程,使用时直接调用即可 存储过程的优点: 语句已经经过优化,所其以运行效率高 降低了客户机和服务器之间的通信量,只有最终的处理结果才会返回客户端 方便实施企业规则 存储过程定义 存储过程的通用格式如下 12345CREATE PROCEDURE <存储过程名> ([[参数模式 参数名 参数类型],...])[characteristics...]BEGIN <存储过程体>END 其中characteristics指定存储过程特性,取值如下: LANGUAGE SQL:说明body部分由SQL语句组成,LANGUAGE可选值只有SQL [NOT] DETERMINISTIC:指明存储过程执行结果是否确定。默认值:NOT DETERMINISTIC DETERMINISTIC:结果确定,每次执行存储过程时,相同的输入会得到相同的输出 NOT DETERMINISTIC:结果不确定,相同输入可能得到不同输出。 {CONTAINS SQL | NO SQL | READS SQL DATA | MODIFIES SQL DATA}:指定子程序使用存储过程的限制。默认值:CONTAINS SQL CONTAINS SQL:说明子程序包含SQL语句,但是不包含写数据语句 NO SQL:说明子程序不包含SQL语句 READS SQL DATA:说明子程序包含读数据读数据语句 MODIFIES SQL DATA:说明子程序包含写数据语句 SQL SECURITY {DEFINER | INVOKER}:指明谁有权限执行,默认值:DEFINER DEFINER:只有定义者才能执行 INVOKER:拥有权限的调用者才可以执行 COMMNET:注释信息 如下定义了一个名叫exp6_1的存储过程,它的功能为如果没有名叫test的表,则创建一个test表 1234567DELIMITER $ /*告诉mysql语句的结尾符号换成以$结束*/CREATE PROCEDURE exp6_1 ()BEGIN DROP TABLE IF EXISTS test; CREATE TABLE test(Num INT);END $DELIMITER ; /*将结尾符号换回以;结束*/ 存储过程运行 存储过程的运行的通用格式如下 12/*存储过程的调用只能用CALL*/CALL <存储过程名>([参数,...]); 调用存储过程exp6_1 123/*调用exp6_1*/CALL exp6_1();SHOW TABLES; 可以看到存储过程exp6_1创建了test表,如下图所示 存储过程更名 由于MySQL并不支持存储过程更名,只能删掉并重新建立存储过程,这里简单介绍一下修改存储过程内容的过程 修改存储过程的通用格式如下 123/*使用ALTER存储过程*/ALTER PROCEDURE <存储过程名> [characterustic...]; 其中characteristics指定存储过程特性,取值如下: {CONTAINS SQL | NO SQL | READS SQL DATA | MODIFIES SQL DATA}:指定子程序使用存储过程的限制。 CONTAINS SQL:说明子程序包含SQL语句,但是不包含写数据语句 NO SQL:说明子程序不包含SQL语句 READS SQL DATA:说明子程序包含读数据读数据语句 MODIFIES SQL DATA:说明子程序包含写数据语句 SQL SECURITY {DEFINER | INVOKER}:指明谁有权限执行,默认值:DEFINER DEFINER:只有定义者才能执行 INVOKER:拥有权限的调用者才可以执行 COMMNET:注释信息 存储过程删除 存储过程删除的通用格式如下 12/*存储过程的删除使用DROP*/DROP PROCEDURE <存储过程名>; 如下展示了如何删除我们之前定义的存储过程exp6_1 12/*删除存储过程exp6_1*/DROP PROCEDURE exp6_1; 存储过程的参数传递 我们假定这样一个场景,设计一个LowerBound的存储过程,它的功能是统计之前定义的test表中比输入的参数的值大的数据的个数,并将统计结果和该参数以及插入时间存入到counts表中 (1)首先我们创建counts表 12/*创建counts表*/CREATE TABLE counts(Total INT, Boud INT, TimeInsert DATETIME); (2)然后我们创建LowerBound存储过程,它的输入参数只有一个bound参数,模式为IN,类型为INT 1234567891011/*创建LowerBound存储过程*/DELIMITER $CREATE PROCEDURE LowerBound(IN bound INT)BEGIN INSERT INTO counts VALUES ( (SELECT COUNT(*) FROM test WHERE Num>bound), bound, CURRENT_TIME() );END $DELIMITER ; (3)之后我们调用LowerBound存储过程,bound值传入为150 12/*调用LowerBound存储过程*/CALL LowerBound(150); (3)最后我们查看一下调用LowerBound的结果,如果没有出错,统计结果应该为49 12/*查看LowerBound的调用结果*/SELECT * FROM counts; 可以看到统计结果为49,边界值Bound为150,插入时间如图所示 函数 自定义函数定义 定义函数的通用格式如下 12345CREATE FUNCTION <函数名> ([[参数名 参数类型],...]) RETURNS <返回值类型>[characteristics...]BEGIN <函数体>END 注意自定义函数与存储过程的区别之一在于函数需要函数体内写RETURN值。区别之二在于,存储过程的参数可有IN、OUT、INOUT模式,而函数的参数没有 其中characteristics指定函数特性,取值如下: LANGUAGE SQL:说明body部分由SQL语句组成,LANGUAGE可选值只有SQL [NOT] DETERMINISTIC:指明函数执行结果是否确定。默认值:NOT DETERMINISTIC DETERMINISTIC:结果确定,每次执行函数时,相同的输入会得到相同的输出 NOT DETERMINISTIC:结果不确定,相同输入可能得到不同输出。 {CONTAINS SQL | NO SQL | READS SQL DATA | MODIFIES SQL DATA}:指定子程序使用函数的限制。默认值:CONTAINS SQL CONTAINS SQL:说明子程序包含SQL语句,但是不包含写数据语句 NO SQL:说明子程序不包含SQL语句 READS SQL DATA:说明子程序包含读数据读数据语句 MODIFIES SQL DATA:说明子程序包含写数据语句 SQL SECURITY {DEFINER | INVOKER}:指明谁有权限执行,默认值:DEFINER DEFINER:只有定义者才能执行 INVOKER:拥有权限的调用者才可以执行 COMMNET:注释信息 如下定义了一个名叫exp6_2的函数,它的功能为向test表中插入给定参数n往后的100个整数,并返回最终停止累加时的数字 1234567891011DELIMITER $ /*告诉mysql语句的结尾符号换成以$结束*/CREATE FUNCTION exp6_2 (P1 INT) RETURNS INTBEGIN DECLARE tmp INT DEFAULT P1+100; WHILE P1 < tmp DO INSERT INTO test VALUES (P1); SET P1 = P1 + 1; END WHILE; RETURN tmp;END $DELIMITER ; /*将结尾符号换回以;结束*/ 自定义函数运行 自定义函数运行的通用格式如下 12/*自定义函数的调用只能用SELECT*/SELECT <自定义函数名>([参数,...]); 如下展示了如何调用我们之前定义的函数exp6_2 接着调用自定义函数exp6_2 123/*调用exp6_2*/SELECT exp6_2(100);SELECT * FROM test; 可以看到调用自定义函数exp6_2的返回值为200,因为是从100开始往后的100个数 最后累加到199停止,共100行,累加停止时的数为200 自定义函数更名 由于MySQL并不支持函数更名,只能删掉并建立新的函数,这里简单介绍一下修改函数内容的过程 修改函数的通用格式如下 123/*使用ALTER修改函数*/ALTER FUNCTION <函数名> [characterustic...]; 其中characteristics指定函数特性,取值如下: {CONTAINS SQL | NO SQL | READS SQL DATA | MODIFIES SQL DATA}:指定子程序使用函数的限制。 CONTAINS SQL:说明子程序包含SQL语句,但是不包含写数据语句 NO SQL:说明子程序不包含SQL语句 READS SQL DATA:说明子程序包含读数据读数据语句 MODIFIES SQL DATA:说明子程序包含写数据语句 SQL SECURITY {DEFINER | INVOKER}:指明谁有权限执行,默认值:DEFINER DEFINER:只有定义者才能执行 INVOKER:拥有权限的调用者才可以执行 自定义函数删除 自定义函数删除的通用格式如下 12/*自定义函数的删除使用DROP*/DROP PROCEDURE <函数名>; 如下展示了如何删除我们之前定义的自定义函数exp6_2 12/*删除自定义函数exp6_2*/DROP FUNCTION exp6_2; 自定义函数的参数传递 我们设计一个A+B函数,功能是输入两个INT类型的值,返回值为这两个输入参数的和 (1)首先创建自定义函数A+B,函数名为AplusB,输入参数为两个INT类型的参数P1和P2,返回值也为INT类型 123456789/*创建自定义函数AplusB*/DELIMITER $CREATE FUNCTION AplusB (P1 INT, P2 INT) RETURNS INTBEGIN DECLARE result INT; SET result = P1 + P2; RETURN result;END $DELIMITER ; (2)调用AplusB并查看结果 12/*调用AplusB函数*/SELECT AplusB(10, 20); 可以看到相加结果为10+20=30,结果正确 游标 游标定义 游标简介: 游标实际上是一种能从包括多条数据记录的结果集中每次提取一条记录的机制。 游标充当指针的作用。 尽管游标能遍历结果中的所有行,但它一次只指向一行。 游标的作用就是用于对查询数据库所返回的记录进行遍历,以便进行相应的操作。 游标必须声明在处理程序之前,并且声明在变量和条件之后 MySQL中使用DECLARE来声明游标,通用格式如下 1DECLARE <游标名字> CURSOR FOR <SELECT语句>; 我们如下创建一个名为exp6_3的游标,它的功能是选出那些在test表中Num值比170大的元组 12DECLARE exp6_3 CURSOR FOR SELECT 数量 FROM test WHERE Num>170; 游标使用 由于游标需要配合存储过程或自定义函数来使用,这里我们创建一个存储过程Transform,设计一个游标,将test表中Num比bound参数大的元组插入到另一个表test2中 详细的运行过程已经以注释的形式写在代码中 123456789101112131415161718192021DELIMITER $CREATE PROCEDURE Transform(IN bound INT)BEGIN DECLARE tmp INT; DECLARE done int; /*声明游标exp6_3*/ DECLARE exp6_3 CURSOR FOR SELECT Num FROM test WHERE Num>bound; /*游标中的内容执行完后将done设置为1*/ DECLARE CONTINUE HANDLER FOR NOT FOUND SET done=1; /*打开游标*/ OPEN exp6_3; /*使用REPEAT循环从游标中读取数据*/ REPEAT FETCH exp6_3 INTO tmp; INSERT INTO test2 VALUES (tmp); UNTIL done END REPEAT; /*关闭游标*/ CLOSE exp6_3;END $DELIMITER ; 之后我们调用存储过程Transform 1CALL Transform(190); 最后我们检查运行结果,查看表test2中的内容 1SELECT * FROM test2; 可以看到该运行结果符合我们的预设的功能 ODBC编程 开放数据库连接(Open Database Connectivity,ODBC)是为解决异构数据库间的数据共享而产生的,它建立了一组规范,并提供了一组访问数据库的应用程序编程接口(API) ODBC具有两重约束力:一方面规范应用开发,另一方面规范关系数据库管理系统应用接口 ODBC有4部分:用户驱动程序管理器、数据库驱动程序管理器、数据库驱动程序、数据源","categories":[{"name":"数据库原理","slug":"数据库原理","permalink":"https://godway999.github.io/categories/数据库原理/"}],"tags":[]},{"title":"模式匹配算法(KMP+字典树+AC自动机)","slug":"Algorithm1","date":"2019-05-16T01:20:06.000Z","updated":"2019-06-11T00:57:27.015Z","comments":true,"path":"2019/05/16/Algorithm1/","link":"","permalink":"https://godway999.github.io/2019/05/16/Algorithm1/","excerpt":"","text":"KMP算法:1对1模式匹配 参考地址 1对1的意思是给定一个单词看是否在某个文章(长字符串)中出现 123456789101112131415161718192021// 计算next数组public static int[] getNext(String ps) { char[] p = ps.toCharArray(); int[] next = new int[p.length]; next[0] = -1; int j = 0; int k = -1; while (j < p.length - 1) { if (k == -1 || p[j] == p[k]) { if (p[++j] == p[++k]) { // 当两个字符相等时要跳过 next[j] = next[k]; } else { next[j] = k; } } else { k = next[k]; } } return next;} 1234567891011121314151617181920212223242526//完整代码public static int KMP(String ts, String ps) { char[] t = ts.toCharArray(); char[] p = ps.toCharArray(); int i = 0; // 主串的位置 int j = 0; // 模式串的位置 int[] next = getNext(ps); while (i < t.length && j < p.length) { if (j == -1 || t[i] == p[j]) { // 当j为-1时,要移动的是i,当然j也要归0 i++; j++; } else { // i不需要回溯了 // i = i - j + 1; j = next[j]; // j回到指定位置 } } if (j == p.length) { return i - j; } else { return -1; }} 字典树:1对多模式匹配 1对多的意思是指给定一个单词,看是否是否出现在一个给定的字典(包含多个单词)中 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364#include <iostream>#include <unistd.h>#include <pthread.h>#include <string>using namespace std;class TrieNode{ // 字典树节点public: int num;// 有多少单词通过这个节点,即由根至该节点组成的字符串模式出现的次数 // TrieNode** son;// 所有的儿子节点 TrieNode* son[26]; bool isEnd;// 是不是最后一个节点 char val;// 节点的值 TrieNode(){ num = 1; // son = new TrieNode*[26]; isEnd = false; } ~TrieNode(){ // for(int i = 0; i < 26; i++){ // delete son[i]; // } // delete son; }}root;// 建立字典树void insert(string str){ // 在字典树中插入一个单词 TrieNode* node = &root; for (int i = 0, len = str.length(); i < len; i++){ int pos = str[i] - 'a'; if (node->son[pos] == NULL) //如果当前节点的儿子节点中没有该字符,则构建一个TrieNode并复值该字符 { node->son[pos] = new TrieNode; node->son[pos]->val = str[i]; } else //如果已经存在,则将由根至该儿子节点组成的字符串模式出现的次数+1 { node->son[pos]->num++; } node = node->son[pos]; } node->isEnd = true;}// 在字典树中查找一个完全匹配的单词.bool search(string str){ TrieNode* node = &root; for(int i = 0,len = str.length(); i < len; i++){ int pos = str[i] - 'a'; if(node->son[pos] != NULL){ node = node->son[pos]; }else{ return false; } } //走到这一步,表明可能完全匹配,也可能部分匹配,如果最后一个字符节点为末端节点,则是完全匹配,否则是部分匹配 return node->isEnd;}int main(){ return 0;} 以动态分配为实现的带增删改查的字典树模版. 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149//一个以链表实现带删除功能允许重复字符串的字典树#include <stdio.h>#include <string.h>#include <stdlib.h> int charmapping[256]; //字符映射数组,charmapping[i]=x表示ascii码为i的字符对应于treenode中的next[x] void init_charmapping(){ for(int i='a';i<='z';i++){ //我的这个字典树现在只允许输入小写字符组成的字符串,然而由于有charmapping的存在,增加新字符添加映射并且增大maxn就好,很方便. charmapping[i]=i-'a'; } } const int maxn=26; //这里假设字符串中只出现26个小写字母 const int maxm=100000;struct treenode{ int count; //标志此节点所表示字符串在所有字符串中以前缀形式出现的总次数 treenode* next[maxn]; }head; void init_trie(){ head.count=1; //初始化为1包括空串并且避免树头被删 for(int i=0;i<maxn;i++) head.next[i]=NULL;} treenode* createnew(){ //申请一个新结点并初始化它 treenode* newnode; newnode=(treenode*)malloc(sizeof(treenode)); newnode->count=0; for(int i=0;i<maxn;i++) newnode->next[i]=NULL; return newnode;}void update(char* s,int num){ //向字典树添加num个字符串s int k=0,temp; treenode* t=&head; while(s[k]){ t->count+=num; temp=charmapping[s[k]]; if(!t->next[temp]) t->next[temp]=createnew(); t=t->next[temp]; k++; } t->count+=num;}bool search(char* s,int num){ //查找字典树中是否已经存在num个字符串s int k=0,temp; treenode* t=&head; while(s[k]){ temp=charmapping[s[k]]; if(!t->next[temp]||t->next[temp]->count<num) return false; //根本不存在字符串s或者存在的数目小于num直接失败 t=t->next[temp]; k++; } int snum=t->count; for(int i=0;i<maxn;i++) if(t->next[i]) snum-=t->next[i]->count; //这里是核心!!!结点t代表的字符串出现的次数就是总次数减去所有子节点次数和 if(snum>=num) return true; //如果字符串s的数目snum大于等于num return false;}void erase(char* s,int num){ //删除字典树中的num个字符串s并释放无用结点,删除前一定要先search是否存在 int k=0,temp; treenode* t=&head; treenode* t1; //t1后面的结点都是删除后需要被释放的 head.count-=num; while(s[k]){ temp=charmapping[s[k]]; t->next[temp]->count-=num; if(t->next[temp]->count==0){ t1=t->next[temp]; t->next[temp]=NULL; k++; break; } t=t->next[temp]; k++; } while(s[k]){ //释放无用结点 temp=charmapping[s[k]]; t=t1->next[temp]; free(t1); t1=t; k++; } free(t1);}char temp[1000];void printall(treenode* tnode,int pos){ //递归打印字典树咯,打出了就是字典序升序的 int count=tnode->count; for(int i=0;i<maxn;i++) if(tnode->next[i]) count-=tnode->next[i]->count; for(int i=0;i<count;i++) printf(\"\\\"%s\\\"\\n\",temp); for(int i='a';i<='z';i++){ if(tnode->next[charmapping[i]]){ temp[pos]=i; temp[++pos]='\\0'; printall(tnode->next[charmapping[i]],pos); temp[--pos]='\\0'; } }}int main(){ init_charmapping(); //初始化映射 init_trie(); //初始化字典树 char x[1000]; char order; //命令 int num; //数目 printf(\"q:查询\\nu:插入\\nd:删除\\np:打印字典树\\ne:退出\\n\"); while(1){ printf(\"请输入命令:\"); fflush(stdin); scanf(\"%c\",&order); if(order=='q'){ printf(\"请输入要查找的字符串与数目:\"); scanf(\"%s%d\",&x,&num); if(search(x,num)) printf(\"匹配成功。\\n\\n\"); else printf(\"匹配失败,不存在%d个\\\"%s\\\"\\n\\n\",num,x); } else if(order=='u'){ printf(\"请输入要插入的字符串与数目:\"); scanf(\"%s%d\",&x,&num); update(x,num); printf(\"%d个\\\"%s\\\"已加入字典树。\\n\\n\",num,x); } else if(order=='d'){ printf(\"请输入要删除的字符串与数目:\"); scanf(\"%s%d\",&x,&num); if(!search(x,num)){ printf(\"树中无%d个字符串\\\"%s\\\"请重新键入命令!\\n\\n\",num,x); continue; } erase(x,num); printf(\"%d个\\\"%s\\\"已从字典树中删除。\\n\\n\",num,x); } else if(order=='p'){ printf(\"当前字典树内有如下字符串:\\n\"); temp[0]='\\0'; printall(&head,0); } else if(order=='e'){ printf(\"退出ing....\\n\"); break; } else printf(\"无效命令,请重新输入!\\n命令q:查询是否存在字符串\\n命令u:往字典树加入字符串\\n命令d:删除某个字符串\\n命令p:按字典序升序输出字典树\\n命令e:退出程序\\n\\n\"); } return 0;} AC自动机:多对多模式匹配 多对多的意思是指给定多个单词,查看所有单词在给定文章中的出现的次数 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677struct node{ int son[26]; int fail; int count; void init() { memset(son, -1, sizeof(son)); fail = 0; count = 0; }}s[500005];void insert(){ int len = strlen(str); int i, j, ind; for(i = ind = 0; i < len; i++) { j = str[i] - 'a'; if(s[ind].son[j] == -1) { s[sind].init(); s[ind].son[j] = sind++; } ind = s[ind].son[j]; } s[ind].count++;}void make_fail(){ qin = qout = 0; int i, ind, ind_f; for(i = 0; i < 26; i++) { if(s[0].son[i] != -1) { q[qin++] = s[0].son[i]; } } while(qin != qout) { ind = q[qout++]; for(i = 0; i < 26; i++) { //找之后的子节点 if(s[ind].son[i] != -1) { q[qin++] = s[ind].son[i]; ind_f = s[ind].fail; while(ind_f > 0 && s[ind_f].son[i] == -1) ind_f = s[ind_f].fail; if(s[ind_f].son[i] != -1) ind_f = s[ind_f].son[i]; s[s[ind].son[i]].fail = ind_f;//子节点的fail根据父节点fail指针的搞定 } } }}int fd() { int ct = 0; int di, i, ind, p; int len = strlen(des);//这个是文章 for(di = ind = 0; di < len; di++) { i = des[di] - 'a'; while(ind > 0 && s[ind].next[i] == -1) ind = s[ind].fail; if(s[ind].next[i] != -1) {//等于-1的时候就已经是找打了根节点。 ind = s[ind].next[i]; p = ind; while(p > 0 && s[p].count != -1) {//这里是精髓。在找过某个有标记的节点的时候 ct += s[p].count; //答案 //会把该位的标记标记为-1,在下次经过有-1 s[p].count = -1; //标记的时候,说明之后的都被计算过,不用 p = s[p].fail; //再重复计算了。 } } } return ct;}","categories":[],"tags":[]},{"title":"计算机网络——第四章:网络层(数据平面)","slug":"Network4","date":"2019-05-14T11:43:37.000Z","updated":"2019-06-17T11:51:36.403Z","comments":true,"path":"2019/05/14/Network4/","link":"","permalink":"https://godway999.github.io/2019/05/14/Network4/","excerpt":"","text":"参考书目《计算机网络:自顶向下方法(第七版)》 网络层概述 转发和路由选择:数据平面和控制平面 网络层能够分解为两个相互作用的部分:数据平面和控制平面 转发:当一个分组到达某路由器的一条输入链路时,该路由器必须将该分组移动到适当的输出链路 转发是在数据平面中实现的唯一功能 转发(forwarding)是指将分组从一个输入链路接口转移到适当的输出链路接口的路由器本地动作 转发发生的时间尺度很短(通常为几纳秒),因此常用硬件来实现 路由选择:当分组从发送方流向接收方时,网络层必须决定这些分组所采用的路由或路径 计算这些路径的算法被称为路由选择算法 路由选择(routing)是指确定分组从源到目的地所采取的端到端路径的网络范围处理过程 路由选择发生的时间尺度很长(通常为几秒),因此常用软件来实现 网络服务模型 因特网的网络层提供了单一的服务模型,称为尽力而为服务(best-effort service) ATM网络体系结构是面向连接的网络层协议,它提供了确保按序时延、有界时延和确保最小带宽 路由器工作原理 路由器四个组件:输入端口(input port)、交换结构(switch fabric)、输出端口(output port)、路由选择处理器(routing processor) 输入端口 输入端口在路由器中执行终结入物理链路的物理层功能 输入端口还要与位于入链路远端的数据链路层交互来执行数据链路层功能 更为重要的是,它还在输入端口值行查找功能,正是在这里路由器通过查询转发表决定路由器的输出端口 在转发表中匹配时使用最长前缀匹配规则 交换结构 交换结构将路由器的输入端口连接到它的输出端口 交换结构可以有多种形式 经内存交换:当报文到达时中断路由选择处理器,之后被依次复制到处理器内存和输出端口,完成交换 经总线交换:输入端口经一根共享总线将分组直接传送到输出端口 经互联网络交换(纵横式):纵横式交换机是非阻塞的,并且可以并行处理到不同输出端口的分组 输出端口 输出端口存储从交换结构接受的分组,并通过执行必要的链路层和物理层功能在输出链路上传送这些分组 路由选择处理器 路由选择处理器执行控制平面功能: 在传统的路由器中,它执行路由选择协议 在SDN路由器中,它负责与远程控制器通信 分组调度 先进先出(FIFO) 优先队列 循环排队 加权公平排队(WFQ) IPv4 IPv4数据报格式 版本号(4 bit);规定了数据报的IP协议版本 首部长度(4 bit);由于可变选项,首部长度用来确定数据报中载荷实际开始的位置,一般IP数据报具有20字节首部 服务类型TOS(8 bit);使不同类型的IP数据报能相互区别开 数据报长度(16 bit);表示IP数据报的总长度(首部加上数据),以字节计 标识(16 bit)、标志(1 bit)、片偏移(15 bit):用于IP分片 TTL(8 bit);每经过一个路由器TTL减1,当TTL为0时,路由器丢弃该数据报。用于防止路由回路 上层协议(8 bit);当数据报到达目的地时才起到作用,该字段用于指明IP数据报的数据部分用于交给哪个特定的运输层协议(值为6表示给TCP,为17给UDP),协议号是将网络层与运输层绑定到一起的粘合剂,类似于端口号粘合运输层和应用层 首部检验和(16 bit);帮助路由器监测收到的IP数据报中的比特错误。 为什么TCP?IP在运输层和网络层都执行差错检测? (1)IP层只对IP首部计算了检验和,而TCP/UDP检验和是对整个TCP/UDP报文段进行 (2)TCP/UDP与IP不一定必须属于同一个协议栈。例如TCP可以运行在ATM上,IP也不一定要携带传给TCP/UDP的数据(ICMP报文) 源和目的IP地址(32 bit);发送端和接收端的IP地址 IPv4分片 一个链路层帧能够承载的最大数据量叫最大传输单元(MTU),MTU严格的限制着IP数据报的长度 源和目的地之间的路径上可能存在不同的MTU,有时需要将过大IP数据报分成小的片来通过链路,并且片的重新组装是端系统的任务 形成的所有片的标识号都与原数据报一致 为使目的主机确定初始数据报的最后一片已到达,最后一个片的标志比特被设为0,其余的标志比特都为1 为了重组原数据报,使用片偏移指定当前片在初始IP数据报中的偏移位置(以字节为单位做偏移) IPv4编址 IP地址分为两个部分:网络号和主机号 IP地址的种类: A类:0 + 网络号(7位)+ 主机号(24位) B类:10 + 网络号(6+8位)+ 主机号(16位) C类:110+ 网络号(5+8+8位)+ 主机号(8位) D类:1110 + 组播地址(28位) E类:11110保留为今后用 私有网络地址(RFC 1918): A类:10.0.0.0至10.255.255.255 B类:172.16.0.0至172.31.255.255 C类:192.168.0.0至192.168.255.255 子网划分方法: 典型的子网划分(RFC 950) 一般子网划分(可变长子网掩码,VLSM) 无类别域间路由(CIDR) CIDR的形式:a.b.c.d/x,x指示了地址中网络号的比特数。一个地址的剩余32 - x比特可认为是用于区分该组织内部设备的,其中所有的设备具有相同的网络前缀,当组织内部的路由器转发分组时,才会考虑这些比特 使用单个网络前缀通告多个网咯的能力通常称为地址聚合,或称为路由聚合、路由摘要 在寻址中使用最长前缀匹配 IPv6 IPv6报文格式 版本;标识IP版本号,IPv6将该字段设置为6 流量类型;和IPv4的TOS字段含义相似 流标签;用于标识一条数据报的流,能够对一条流中的某些数据报给出优先权 有效载荷长度;给出有效载荷的字节数量 下一个首部;与IPv4首部中协议字段相同,用于标识数据应该交付给哪个协议 跳限制;IPv4中的TTL IPv6引入的重要的变化有: 扩大的地址容量;IPv6将地址长度扩充到128比特。IPv6还引入了一种称为任播地址的新型地址,这种地址可以使数据报交付给一组主机中的任意一个 简化高效的40字节首部(定长);允许路由器更快的处理IP数据报 流标签;用于区分不同的流 IPv6相对于IPv4删除的字段: 分片/重新组装;IPv6不允许在中间路由器上进行分片与重新组装。分片与重新组装是一个耗时的操作,将该功能从路由器中删除可以加快IP转发速度 首部检验和;因特网的运输层和数据链路层都执行了检验操作,设计者可能觉得在网络层实现该功能实属多余,所以将其删除。再次强调,快速处理IP分组是关注的重点,由于IPv4中的TTL字段,所以在每台路由器上都需要重新计算IPv4首部检验和,这也是一项耗时的操作 选项;不再是标准IP首部的一部分,但并没有消失,而是可能出现在“下一个首部”字段中。删除它使得IP首部成为定长的40字节 动态主机配置协议DHCP(Dynamic Host Configuration) DHCP允许主机自动获取(被分配)一个IP地址(或临时的IP地址) DHCP还允许主机得知其他信息,如它的子网掩码、它的第一跳路由器地址(通常称为默认网关)与它的本地DNS服务器地址 DHCP分为4个步骤 DHCP服务器发现;新到达的主机广播DHCP发现报文(使用UDP分组向67端口发送该报文)来与DHCP服务器交互,广播IP地址为255.255.255.255,源IP地址为0.0.0.0 DHCP服务器提供;DHCP服务器广播DHCP提供报文(包含IP地址租用期)回复发送主机,仍使用IP广播地址255.255.255.255 DHCP请求;新到达的主机从一个或多个服务器提供中选择一个DHCP服务器,并向选中的DHCP服务器回复DHCP请求报文进行响应 DHCP ACK;DHCP服务器用DHCP ACK报文对DHCP请求报文进行响应 网络地址转换NAT(Network Address Translation) NAT路由器对外界的行为就如同一个具有单一IP地址的单一设备,本质上讲,NAT使能路由器对外界隐藏了私有网络的内部细节 NAT路由器通过维护NAT转换表,重写经过它的数据报的目的IP地址与端口号,从而完成内网到外网的IP地址和端口转换(因为端口号字段长度为16比特,从而NAT协议可支持超过60000个并行使用路由器广域网一侧单个IP地址的连接) NAT违反了主机应当直接彼此对话这个原则,并且变相利用端口号用于主机寻址 因特网控制报文协议ICMP(Internet Control Message Protocol) ICMP定义于RFC 792,被主机和路由器用来彼此沟通网络层的信息 ICMP最典型的用途是差错报告 ICMP从体系结构上讲位于IP之上,因为ICMP报文是承载在IP分组中的,从而可以看成是一个运输层协议 ICMP报文有一个类型字段和一个编码字段,并且包含引起该ICMP报文首次生成的IP数据报的首部和前8个字节 ICMP类型 编码 描述 0 0 回显回答(对ping的回答) 3 0 目的网络不可达 3 1 目的主机不可达 3 2 目的协议不可达 3 3 目的端口不可达 3 6 目的网络未知 3 7 目的主机未知 4 0 源抑制(拥塞控制) 8 0 回显请求 9 0 路由器通告 10 0 路由器发现 11 0 TTL过期 12 0 IP首部损坏","categories":[{"name":"计算机网络","slug":"计算机网络","permalink":"https://godway999.github.io/categories/计算机网络/"}],"tags":[]},{"title":"计算机网络——第三章:运输层","slug":"Network3","date":"2019-05-09T06:18:54.000Z","updated":"2019-07-02T15:46:33.010Z","comments":true,"path":"2019/05/09/Network3/","link":"","permalink":"https://godway999.github.io/2019/05/09/Network3/","excerpt":"","text":"参考书目《计算机网络:自顶向下方法(第七版)》 概述和运输层服务 网络层提供了主机之间的逻辑通信,而运输层为运行在不同主机上的进程之间提供了逻辑通信 运输协议能够提供的服务不一定受制于底层网络层协议的服务模型。例如,即使网络协议不可靠或不保证机密性,运输协议也能提供可靠的数据传输或加密服务 IP的服务模型是尽力而为(best-effort)交付服务,它不保证报文段的交付、按序到达或完整性。从而IP被称为不可靠服务 将主机间交付扩展到进程间交付被称为运输层的多路复用和多路分解 进程到进程的数据交付和差错检查是两种最低限度的运输层服务,也是UDP所能提供的仅有的两种服务 多路复用与多路分解 多路复用:从不同套接字中收集数据块并为每个数据块封装上首部信息生成报文段,之后将报文段传递到网络层 多路分解:运输层报文段中的数据交付到正确的套接字 主机使用IP地址和端口号来将报文段导向合适的套接字(socket) UDP的多路复用与多路分解 一个UDP套接字由一个二元组全面标识,该二元组包含一个目的IP地址和一个目的端口号 如果两个UDP报文段拥有不同的源IP地址或(/和)源端口号,但具有相同的目的IP地址和目的端口号,那么这两个报文段将通过相同的目的套接字被定向到相同的目的进程 TCP的多路复用与多路分解 一个TCP套接字由一个四元组(源IP地址,源端口号,目的IP地址,目的端口号)来标识的 两个具有不同源IP地址或源端口号的到达TCP报文段将被定向到两个不同的套接字,除非TCP报文段携带了初识创建连接的请求(例如Web服务器的80端口) Web服务器与TCP 连接套接字与进程之间并非总是有着一对一的关系;事实上。当今高性能Web服务器通常只使用一个进程,但是为每个新的客户连接创建一个具有新连接套接字的新线程 对于服务器来说,在任意给定时间都有可能有(具有不同标识的)许多连接套接字连接到相同的进程 无连接运输:UDP 运输层最低限度必须提供一种复用/分解服务,以便在网络层与正确的应用级进程之间传递数据 由[RFC 768]定义的UDP只是做了运输层协议能够做的最少工作 UDP被称为是无连接的,因为在发送报文段之前,发送方和接收方的运输层实体之间没有握手 许多使用UDP的原因 关于发送什么数据以及和何时发送的应用层控制更为精细 封装报文段的速度快 TCP会受到拥塞控制机制的遏制,而UDP不会。因为一些实时应用通常要求最小的发送速率,不希望过分地延迟报文段的传送,且能容忍一些数据丢失 无须连接建立 UDP不需要任何准备即可进行数据传输。因此UDP不会引入建立连接的时延,这可能是DNS运行在UDP之上的主要原因 无连接状态 UDP不像TCP维护连接状态(接受和发送缓存、拥塞控制参数、序号和确认号的参数)。因而当某些应用程序运行在UDP之上而不是TCP之上时,一般都能支持更多的活跃客户 分组首部开销小 TCP每个报文段都有20字节的首部开销,而UDP仅有8字节 注意:使用UDP的应用是可能实现可靠数据传输的。这可通过在应用程序自身中建立可靠性机制来完成(谷歌的Chrome浏览器使用的QUIC协议在UDP之上的应用层协议中实现了可靠性) UDP报文结构 长度字段指明了包括首部在内的UDP报文段长度(以字节为单位) 检验和(checksum)用于差错检测功能 发送方对报文段中的所有16比特字(检验和的位置被认为是全0)进行求和(求和时的溢出都被回卷),将结果的和进行反码运算并存为UDP报文段中的检验和 接收方只要将全部的16比特字(包括检验和)进行相加,若结果不全为1,则表示该分组中出现了差错 计算检验和的时候不足16比特字时使用0填充(zero padding) 提供检验和的原因是:不能保证源和目的之间的所有链路都提供差错检测 端到端原则:某些功能(例如差错检测)必须基于端到端实现,因为“与在较高级别提供这些功能的代价相比,在较低级别上设置的功能可能是冗余的或几乎没有价值的” 可靠数据传输原理 可靠数据传输为上层实体提供的服务抽象是:数据可以通过一条可靠的信道进行传输。实现这种抽象的是可靠数据传输协议(reliable data transfer, rdt) 可靠数据传输机制及其用途的总结 检验和:用于检测在一个传输分组中的比特错误 确认(ACK):接收方用于告诉发送方一个分组或一组分组已经被正确的接收到了 确认报文通常携带着被确认的分组或多个分组的序号 确认报文可以是逐个的或累积的,这取决于协议 序号:用于为从发送方流向接收方的数据分组按顺序编号 所接收分组的序号间的空隙可使接收方检测出丢失的分组 具有相同序号的分组可使接收方检测出一个分组的冗余副本 否定确认(NAK):接收方用于告诉发送方某个分组未被正确的接收。 冗余ACK(duplicated ACK):用于实现与NAK一样的效果 定时器:用于超时/重传一个分组,因为该分组(或其ACK)在信道中丢失了 由于当一个分组延时但未丢失(过早超时),或当一个分组已被接收方收到但从接受方到发送方的ACK丢失时,可能产生超时事件,所以接受方可能会收到一个分组的多个冗余副本 窗口、流水线:发送方也许被限制仅发送那些序号落在一个指定范围内的分组。 通过允许一次发送多个分组但未被确认,发送方的利用率可在停等操作模式的基础上得到增加。 窗口长度可根据接收方接收和缓存报文的能力、网络中的拥塞程度来进行设置 流水线可靠数据传输协议 假定发送速率为\\(R\\)bps,所有分组长度为\\(L\\)比特,定义信道利用率为:发送方实际忙于将发送比特送进信道的那部分时间与发送时间之比 \\[U_{sender} = \\frac{\\frac{L}{R}}{RTT + \\frac{L}{R}}\\] 使用流水线可以显著增加信道利用率,其中\\(W\\)表示窗口大小 \\[U_{sender} = \\frac{W \\times \\frac{L}{R}}{RTT + \\frac{L}{R}}\\] 流水线要求每个输送中的分组(不计算重传)必须有一个唯一的序号;协议的发送方和接收方也许不得不缓存多个分组 解决流水线差错恢复有两种基本方法:回退N步(GBN)和选择重传(SR) 流水线差错恢复:GBN(Go-Back-N) 基序号(send_base):最早未确认分组的序号 下一个序号(nextseqnum):最小的未使用序号(即下一个待发分组的序号) N被称为窗口长度(window size),因而GBN协议也被称为滑动窗口协议 四个区间: 区间[0, send_base - 1]内的序号对应用于已经发送并被确认的分组 区间[send_base, nextseqnum - 1]内的序号对应已被发送但未被确认的分组 区间[nextseqnum, send_base + N - 1]内的序号能用于那些要被立即发送的分组 大于等于send_base + N的序号是不能使用的 GBN发送方需响应三种类型的事件 上层的调用 收到一个ACK 超时事件 GBN对序号为n的分组的确认采取累计确认 GBN接收方丢弃所有失序分组,并不缓存失序分组,其所需要维护的唯一信息就是下一个按序接收的分组的序号 丢弃一个正确接收的分组的缺点是随后对该分组的重传也许会丢失或出错,因此甚至需要更多的重传 流水线差错恢复:SR(Selective Repeat) 选择重传(SR)协议通过让发送方仅重传那些它怀疑在接收方丢失或受损的分组而避免了不必要的重传 SR接收方确认一个正确接收的分组而不管其是否按序 注意: 接收方对于收到的序号小于当前窗口基序号的分组,需要重新回复一个ACK确认(而不是忽略他们)。因为对于SR协议,发送方和接收方的窗口并不总是一致的。 由于发送方和接收方的窗口不一定是一致的,从而窗口长度必须小于或等于序号空间大小的一半 面向连接的运输:TCP TCP提供的是全双工(数据可以双向传输)、点对点(连接仅限于两台主机)的服务 MTU,即最大传输单元(Maximum Transmission Unit),表示物理接口(数据链路层)提供给其上层(通常是IP层)单次最大传输数据的大小,也表示从源到目的地的所有链路上发送的最大链路层帧 MSS,即最大报文段长度(Maximum Segment Size),表示TCP提交给网络层最大分段的大小,指报文段里数据的最大长度,不是指包括首部的TCP报文段的最大长度 MSS是TCP用来限制应用层的最大发送字节数,是TCP能发送的分组的最大长度 MSS是系统默认的,就是系统TCP/TP栈所能允许的最大包。在建立连接时,这个值已经确定了,这个值并不是客观的值,而是由TCP/IP的实现确定的 以太网和PPP链路层协议都具有1500字节的MTU,因此MSS的典型值为1460字节(1500 - 20(IP首部)- 20(TCP首部) = 1460) TCP报文结构 序号(Seq):序号建立在传送的字节流之上,因此一个报文段的序号是该报文段首字节的字节流编号 TCP连接的双方均可随机地选择初始序号 确认号(ACK):主机A填充进报文段的确认号是主机A期待从主机B收到的下一字节的编号 TCP使用累计确认 往返时间的估计与超时 TCP使用超时/重传机制来处理报文段的丢失 SampleRTT:某报文段被交给网络层到对该报文段的确认被收到之间的时间量 EstimatedRTT:对SampleRTT使用指数加权移动平均得到,\\(\\alpha\\)的推荐值为0.125 \\[EstimatedRTT = (1 - \\alpha) \\times EstimatedRTT + \\alpha \\times SampleRTT\\] DevRTT:用于估计SampleRTT偏离EstimatedRTT的程度 \\[DevRTT = (1 - \\beta) \\times DevRTT + \\beta \\times |SampleRTT - EstimatedRTT|\\] TimeoutInterval定义为经验上的TCP超时重传间隔,推荐的初始值为1秒 \\[TimeoutInterval = EstimatedRTT + 4 \\times DevRTT\\] 流量控制 流量控制的目的是为了消除发送方使接收方缓存溢出的可能性 TCP连接管理 建立TCP连接的三次握手: 第一步:客户端的TCP首先向服务端发送SYN报文段,其中SYN比特被置为1,同时客户会随机选择一个初始序号Seq(client_isn)并封装到该报文段中 第二步:服务端回复SYNACK报文段,其中SYN比特被置为1,该报文段的ACK被置为client_isn + 1,最后服务端选择自己的初始序号Seq(server_isn)并封装到该报文段中 客户端对收到SYNACK报文段进行回复。将该报文的ACK置为server_isn + 1,同时将SYN比特置为0。第三次握手可以在报文段负载客户端到服务端的数据 断开TCP连接的四次挥手: 客户端发送FIN给服务端 服务端收到FIN并回复ACK,并发送FIN,准备关闭连接 客户端收到FIN并回复ACK,并发送FIN,然后关闭连接 服务端收到ACK,关闭连接 拥塞控制原理 网络拥塞的代价: 分组的到达速率接近链路容量时,分组将经历巨大的排队时延 发送方必须执行重传以补偿因为缓存溢出而丢弃的分组 发送方在遇到大时延时所进行的不必要重传会引起路由器利用其链路带宽来转发不必要的分组副本 当一个分组沿一条路径被丢弃时,每个上游路由器用于转发该分组到丢弃该分组而使用的传输容量最终被浪费掉了 拥塞控制方法: 端到端拥塞控制。端系统需对网络行为的观察(如丢失与时延)来推断网络状况。如TCP 网络辅助的拥塞控制。在网络辅助的拥塞控制中,路由器向发送方提供关于网络中拥塞状态的显式反馈信息。如显式拥塞控制ECN TCP拥塞控制 一图胜千言。。。 \\[一条连接的平均吞吐量 = \\frac{1.22 \\times MSS}{RTT \\sqrt{L}}\\] TCP拥塞控制发展演进 Tahoe 是 TCP 的早期版本,包括3 个最基本的拥塞控制算法:“慢启动” , “拥塞避免”和“快速重传”,“快速重传”根据 3 个重复的应答报文来判断报文的丢失,减少了超时重传的发生. Reno 在 Tahoe的基础上增加了“快速恢复”[25].“快速恢复”使用“管子”模型的“报文守恒”特性.发送方每收到一个重复的应答,就认为已经有一个报文离开网络,于是将发送方的拥塞窗口加一. NewReno 对 Reno中“快速恢复”算法进行了补充.它考虑了一个发送窗口内多个报文丢失的情况.在“快速恢复”算法中,发送方收到一个不重复的应答后就退出“快速恢复”状态.而在NewReno 中,只有当所有报文都被应答后才退出“快速恢复”状态. SACK 也关注一个窗口内多个报文的丢失,它使用“选择性重复”(selective repeat)策略 TCP Vegas通过观察TCP连接中RTT值改变感知网络是否发生拥塞,从而控制拥塞窗口大小","categories":[{"name":"计算机网络","slug":"计算机网络","permalink":"https://godway999.github.io/categories/计算机网络/"}],"tags":[]},{"title":"计算机网络——第二章:应用层","slug":"Network2","date":"2019-05-07T12:41:41.000Z","updated":"2019-06-17T11:50:06.552Z","comments":true,"path":"2019/05/07/Network2/","link":"","permalink":"https://godway999.github.io/2019/05/07/Network2/","excerpt":"","text":"参考书目《计算机网络:自顶向下方法(第七版)》 应用层协议原理 网络核心设备并不在应用层上起作用,而仅在较低层起作用,特别是在网络层及下面层次起作用 网络应用程序体系结构: 客户-服务器体系结构 P2P体系结构(优秀的特点自扩展性) 可供应用程序使用的传输服务 可靠数据传输 吞吐量 定时(能在给定时间内完成通信) 安全性 TCP服务: 面向连接的服务 可靠的数据传输服务 流量控制 拥塞控制 不提供:定时、最小吞吐量保证、安全性 UDP服务 仅提供最小服务 不可靠数据传输服务 到达接受进程的报文可能是乱序到达 应用层协议定义了运行在不同端系统上的应用进程如何相互传递报文,特别是其定义了: 交换的报文类型,例如请求报文和响应报文 各种报文类型的语法,如报文中的各个字段及这些字段是如何描述的。 字段的语义,即这些字段中的信息的含义 确定一个进程何时以及如何发送报文,对报文进行响应的规则 Web和HTTP Web的应用层协议是超文本传输协议(HyperText Transfer Protocol, HTTP),定义在[RFC 1945]和[RFC 2616] 每个URL地址由两部分组成:存放对象的服务器主机名和对象的路径名 Web浏览器——>HTTP的客户端,Web服务器———>HTTP的服务器端。Web服务器用于存储Web对象,每个对象由URL寻址 HTTP定义了Web客户与Web服务器间间的Web页面的交互方式 因为HTTP服务器不保存关于客户的任何信息,所以HTTP是一个无状态协议 HTTP连接方式:持续连接和非持续连接 对于持续连接: 每次总的响应时间为2个RTT加上服务器传输HTML文件的时间(三次握手+文件传输) 缺点: 必须为每个请求的对象建立和维护一个全新的连接 每个对象经受两倍RTT的交付时延 HTTP默认模式是使用带流水线的持续连接 HTTP报文有两种:请求报文和响应报文 请求报文结构:请求行、首部行、实体 请求行:方法(GET,POST,HEAD,PUT,DELETE)、URL、HTTP版本 响应报文结构:状态行、首部行、实体 状态行包括协议(HTTP)版本、状态码、状态信息 常见状态码和相关短语: 200 OK:请求成功,信息在返回的响应报文中 301 Moved Permanently:请求的对象已被永久转移,新的URL定义在响应报文中 400 Bad Request:该请求不能被服务器理解 404 Not Found:被请求的文档不在服务器上 505 HTTP Version Not Supported:服务器不支持请求报文使用的HTTP版本协议 由于HTTP服务器是无状态的,然而有些时候Web站点希望能够识别用户,为此HTTP使用了cookie,它允许站点对用户进行跟踪 Web缓存器也叫代理服务器,它是能够代表初始Web服务器来满足HTTP请求的网络实体 部署Web缓存器的两个理由: 可以大大减少对客户请求的响应时间,特别是当客户与目标服务器之间的瓶颈带宽远低于客户与Web缓存器之间的瓶颈带宽时 可以大大减少一个机构的接入链路到因特网的通信量,使其不必急于增加带宽,从而降低费用 条件GET方法:用于判断缓存在代理服务器上的内容是否是最新的 因特网中的电子邮件 因特网电子邮件系统有三个主要组成部分: 用户代理(user agent) 邮件服务器(mail server) 简单邮件传输协议(Simple Mail Transfer Protocol, SMTP) SMTP用于从发送方的邮件服务器发送报文到接收方的邮件服务器 SMTP限制所有邮件报文的体部分(不只是其首部)只能采用简单的7比特ASCII表示 SMTP一般不使用中间邮件服务器发送邮件,即使这两个邮件服务器位于地球的两端 SMTP与HTTP的对比: HTTP主要是一个拉协议(pull protocol),用户使用HTTP从服务器上拉取信息;SMTP基本上是一个推协议(push protocol),发送邮件服务器把文件推到接收邮件服务器 SMTP要求每个报文采用7比特ASCII码格式;HTTP则不受这种限制 HTTP把每个对象封装到它自己的HTTP响应报文中;SMTP则把所有报文对象放在一个报文中 DNS:因特网的目录服务 主机可以用主机名(hostname)标识,如www.google.com;也可以通过IP地址进行标志 域名系统(Domain Name System, DNS)的主要任务是提供一种能进行主机名到IP地址转换的目录服务 DNS是: 一个由分层的DNS服务器实现的分布式、层次数据库 一个使得主机能够查询分布式数据库的应用层协议 DNS运行在UDP之上,使用53号端口 DNS还提供一些别的重要服务: 主机别名 邮件服务器别名(像google邮箱可以使用很多的别名) 负载均衡(使用冗余服务器) DNS层次结构 根DNS服务器:提供TLD服务器的IP地址 顶级域(Top-Level Domain, TLD)DNS服务器:提供权威服务器的IP地址 权威DNS服务器:提供公共可访问主机的IP地址 DNS查询有迭代和递归两种方式 为了改善时延性能并减少在因特网上到处传输的DNS报文数量,DNS广泛使用了缓存技术 由于DNS缓存,除少数DNS查询以外,根服务器都被绕过了 P2P文件分发 在P2P文件分发中,每个对等方能够向任何其他对等方重新分发他已经收到的文件的任何一部分 优点:自扩展性 视频流和内容分发网 CDN &&& st=>start: 请求主机 op1=>operation: 本地DNS服务器 op2=>operation: 根DNS服务器 op3=>operation: TLD DNS服务器 op4=>operation: 权威DNS服务器 op5=>operation: 本地DNS服务器 e=>end: 请求主机 st->op1->op2->op3->op4->op5->e{\"scale\":1,\"line-width\":2,\"line-length\":50,\"text-margin\":10,\"font-size\":12} var code = document.getElementById(\"flowchart-0-code\").value; var options = JSON.parse(decodeURIComponent(document.getElementById(\"flowchart-0-options\").value)); var diagram = flowchart.parse(code); diagram.drawSVG(\"flowchart-0\", options);","categories":[{"name":"计算机网络","slug":"计算机网络","permalink":"https://godway999.github.io/categories/计算机网络/"}],"tags":[]},{"title":"计算机网络——第一章:计算机网络和因特网","slug":"Network1","date":"2019-05-07T12:41:31.000Z","updated":"2019-06-17T11:49:42.304Z","comments":true,"path":"2019/05/07/Network1/","link":"","permalink":"https://godway999.github.io/2019/05/07/Network1/","excerpt":"","text":"参考书目《计算机网络:自顶向下方法(第七版)》 什么是因特网 通常把与因特网相连的计算机和其他设备称为端系统 端系统通过通信链路和分组交换机连接在一起 分组交换机:路由器和链路层交换机 链路层交换机通常用于接入网,而路由器通常用于网络核心中 端系统通过因特网服务提供商(Internet Service Provider, ISP)接入因特网 因特网标准(Internet Standard)由因特网工程任务组(Internet Engineering Task, Force, IETF)研发,IETF的标准文档称为请求评论(Request For Comment, RFC) 网络边缘 接入网是指将端系统物理连接到其边缘路由器的网络 家庭接入:数字用户线(Digital Subscriber Line, DSL)、电缆、光纤到户(Fiber To The Home, FTTH)、拨号和卫星 企业(和家庭接入):以太网、WiFi 广域无线接入:4G和LTE 因特网传输的物理媒介: 导引型媒介:双绞铜线、同轴电缆、光纤 非导引型媒介:陆地无线电信道、卫星无线电信道 网络核心 通过网络链路和交换机移动数据有两种基本方法:电路交换和分组交换 分组交换 源将长报文划分为较小的数据块,称之为分组 多数分组交换机在链路的输入端使用存储转发机制,存储转发传输是指在交换机能够开始向链路传输该分组的第一个比特之前,必须接收到整个分组 分组交换网路采用统计复用(Statistical Multiplexing)原则,意味着在一个处理节点,数据包分组的到达的分布是符合统计学分布(泊松分布);基于统计复用的系统,就叫做排队系统 对于每条相连的链路,该分组交换机具有一个输出缓存(也称为输出队列),它用于存储路由器准备发往那条链路的分组。 分组可能需要承担存储转发时延、排队时延甚至分组丢失 每台路由器具有一个转发表,用于目的地址(或目的地址的一部分)映射成为输出链路。路由选择协议用于自动的设置这些转发表 电路交换 在电路交换网络中,在端系统间通信会话期间,预留了端系统间沿路径通信所需要的资源(缓存,链路传输速率);在分组交换网络中是不预留的 链路中的电路是通过频分复用(FDM)或时分复用(TDM)来实现的,如下图所示 对于FDM 在连接期间链路为每条连接分配一个专用频段,该频段的宽度称为带宽 个人理解:将总带宽根据用户人数划分给每个用户,每个用户只分得总带宽的一部分,但所有用户同一时间互不干扰 对于TDM 时间被划分为固定期间的帧,并且每个帧又被划分为固定数量的时隙,网络在每个帧中为每个连接指定一个时隙,该时隙专门由该连接单独使用 个人理解:类似于操作系统中CPU轮转调度,每个连接轮着使用,并在使用期间内独享物理最大带宽 从而对于TDM,一条电路的传输速率等于帧速率乘以一个时隙中的比特数量 分组交换与电路交换的对比 电路交换在静默期中电路资源被浪费了;创建端到端电路和预留端到端带宽是复杂的 分组交换不适合实时服务,因为它的端到端时延是可变的和不可预测的 分组交换提供了比电路交换更好的带宽共享,允许更多的用户使用网络;它比电路交换更简单、更有效、实现成本更低 分组交换网络中的时延、丢包和吞吐量 时延概述 时延类型: 处理时延(\\(d_{proc}\\)):检查分组首部、确定分组去向、检查差错等 排队时延(\\(d_{queue}\\)):分组在队列中等待被传输的时间 传输时延(\\(d_{trans}\\)):接收到整个分组的时间 用\\(L\\)比特表示分组的长度,用\\(R\\)bps表示从路由器A到路由器B的链路传输速率,则传输时延为\\(\\frac{L}{R}\\) 传播时延(\\(d_{prop}\\)):一个比特从链路的起点到到终点在媒介中传播所需的时间 节点总时延 \\[d_{nodal} = d_{proc} + d_{queue} + d_{trans} + d_{prop}\\] 排队时延和丢包 排队时延对于不同的分组可能是不同的 令\\(a\\)表示分组到达队列的平均速率(a的单位为分组/秒,即pkt/s),传输速率\\(R\\)bps,假定所有分组长度为\\(L\\)比特,则比特到达队列的平均速率是\\(La\\)bps;再假设队列容量为无穷,则流量强度定义为\\(\\frac{La}{R}\\) 平均排队时延与流量强度的关系如下 \\(\\frac{La}{R} \\rightarrow 0\\)平均排队时延很小 \\(\\frac{La}{R} \\rightarrow 1\\)排队时延趋进于无穷 实际中队列容量是有限的,因而当队列容量满时,路由器将丢弃新到达的分组,也就是丢包 吞吐量 瞬间吞吐量指主机在某一时刻接受文件的速率 平均吞吐量\\(\\frac{F}{T}\\)bps表示接收到所有\\(F\\)比特用了\\(T\\)秒 吞吐量取决于数据流过的链路的传输速率。也就是说,其近似为沿着源和目的地之间路径的最小传输速率 协议层次及其服务模型 分层的优点 改变服务的实现而不影响该系统其他组件(利于维护更新) 简化网络系统 分层的缺点 高层可能冗余较低层的功能(例如许多协议在基于每段链路和基于端到端两种情况下,都提供了差错恢复) 某层的功能可能需要仅在其他某层才出现的信息(如时间戳值),这违反了层次分离的目标 TCP/IP的5层协议栈,在每一层,一个分组具有两种两种类型的字段:首部字段和有效载荷字段。有效载荷通常是来自上一层的分组 自上而下 载体 协议 应用层 message FTP,SMTP,HTTP 运输层 segment TCP,UDP 网络层 datagram/packet IP,路由协议 链路层 frame PPP,以太网 物理层 bit/Byte - OSI将计算机网络体系结构(architecture)划分为以下七层: 应用层: 提供应用程序间通信 表示层: 处理数据格式、数据加密等(表示层的目的是表示出用户看得懂的数据格式,实现与数据表示有关的功能。 主要完成数据字符集的转换,数据格式化和文本压缩,数据加密、解密等工作) 会话层: 建立、维护和管理会话 传输层: 建立主机端到端连接 网络层: 寻址和路由选择 数据链路层: 提供介质访问、链路管理等 物理层: 比特流传输","categories":[{"name":"计算机网络","slug":"计算机网络","permalink":"https://godway999.github.io/categories/计算机网络/"}],"tags":[]},{"title":"Markdown中Latex常用符号","slug":"Others1","date":"2019-05-04T08:24:28.000Z","updated":"2020-03-10T12:25:36.565Z","comments":true,"path":"2019/05/04/Others1/","link":"","permalink":"https://godway999.github.io/2019/05/04/Others1/","excerpt":"","text":"参考转载出处 常用希腊字母表 Name Display Capital Case Display Var Case Display \\alpha \\(\\alpha\\) \\beta \\(\\beta\\) \\gamma \\(\\gamma\\) \\Gamma \\(\\Gamma\\) \\theta \\(\\theta\\) \\Theta \\(\\Theta\\) \\vartheta \\(\\vartheta\\) \\mu \\(\\mu\\) \\delta \\(\\delta\\) \\Delta \\(\\Delta\\) \\epsilon \\(\\epsilon\\) \\varepsilon \\(\\varepsilon\\) \\sigma \\(\\sigma\\) \\Sigma \\(\\Sigma\\) \\varsigma \\(\\varsigma\\) \\pi \\(\\pi\\) \\Pi \\(\\Pi\\) \\varpi \\(\\varpi\\) \\omega \\(\\omega\\) \\Omega \\(\\Omega\\) \\xi \\(\\xi\\) \\Xi \\(\\Xi\\) \\zeta \\(\\zeta\\) \\chi \\(\\chi\\) \\rho \\(\\rho\\) \\varrho \\(\\varrho\\) \\phi \\(\\phi\\) \\Phi \\(\\Phi\\) \\varphi \\(\\varphi\\) \\eta \\(\\eta\\) \\lambda \\(\\lambda\\) \\Lambda \\(\\Lambda\\) \\kappa \\(\\kappa\\) \\nu \\(\\nu\\) \\upsilon \\(\\upsilon\\) \\Upsilon \\(\\Upsilon\\) \\psi \\(\\psi\\) \\Psi \\(\\Psi\\) \\tau \\(\\tau\\) \\iota \\(\\iota\\) o \\(o\\) 常用特殊字符表 Name Display Name Display Name Display Name Display \\times \\(\\times\\) \\div \\(\\div\\) \\pm \\(\\pm\\) \\mp \\(\\mp\\) \\otimes \\(\\otimes\\) \\ominus \\(\\ominus\\) \\oplus \\(\\oplus\\) \\odot \\(\\odot\\) \\oslash \\(\\oslash\\) \\triangleq \\(\\triangleq\\) \\ne \\(\\ne\\) \\equiv \\(\\equiv\\) \\lt \\(\\lt\\) \\gt \\(\\gt\\) \\le \\(\\le\\) \\ge \\(\\ge\\) \\cup \\(\\cup\\) \\cap \\(\\cap\\) \\Cup \\(\\Cup\\) \\Cap \\(\\Cap\\) \\bigcup \\(\\bigcup\\) \\bigcap \\(\\bigcap\\) \\ast \\(\\ast\\) \\star \\(\\star\\) \\bigotimes \\(\\bigotimes\\) \\bigoplus \\(\\bigoplus\\) \\circ \\(\\circ\\) \\bullet \\(\\bullet\\) \\bigcirc \\(\\bigcirc\\) \\amalg \\(\\amalg\\) \\to \\(\\to\\) \\infty \\(\\infty\\) \\vee \\(\\vee\\) \\wedge \\(\\wedge\\) \\lhd \\(\\lhd\\) \\rhd \\(\\rhd\\) \\bigvee \\(\\bigvee\\) \\bigwedge \\(\\bigwedge\\) \\unlhd \\(\\unlhd\\) \\unrhd \\(\\unrhd\\) \\sqcap \\(\\sqcap\\) \\sqcup \\(\\sqcup\\) \\prec \\(\\prec\\) \\succ \\(\\succ\\) \\subset \\(\\subset\\) \\supset \\(\\supset\\) \\sim \\(\\sim\\) \\approx \\(\\approx\\) \\subseteq \\(\\subseteq\\) \\supseteq \\(\\supseteq\\) \\cong \\(\\cong\\) \\doteq \\(\\doteq\\) \\setminus \\(\\setminus\\) \\mid \\(\\mid\\) \\ll \\(\\ll\\) \\gg \\(\\gg\\) \\parallel \\(\\parallel\\) \\Join \\(\\Join\\) \\in \\(\\in\\) \\notin \\(\\notin\\) \\propto \\(\\propto\\) \\neg \\(\\neg\\) \\ldots \\(\\ldots\\) \\cdots \\(\\cdots\\) \\forall \\(\\forall\\) \\exists \\(\\exists\\) \\vdots \\(\\vdots\\) \\ddots \\(\\ddots\\) \\aleph \\(\\aleph\\) \\nabla \\(\\nabla\\) \\imath \\(\\imath\\) \\jmath \\(\\jmath\\) \\ell \\(\\ell\\) \\partial \\(\\partial\\) \\int \\(\\int\\) \\oint \\(\\oint\\) \\uplus \\(\\uplus\\) \\biguplus \\(\\biguplus\\) 其他符号 Name Display Name Display \\triangleleft \\(\\triangleleft\\) \\triangleright \\(\\triangleright\\) \\bigtriangleup \\(\\bigtriangleup\\) \\bigtriangledown \\(\\bigtriangledown\\) \\uparrow \\(\\uparrow\\) \\downarrow \\(\\downarrow\\) \\leftarrow \\(\\leftarrow\\) \\rightarrow \\(\\rightarrow\\) \\Leftarrow \\(\\Leftarrow\\) \\Rightarrow \\(\\Rightarrow\\) \\longleftarrow \\(\\longleftarrow\\) \\longrightarrow \\(\\longrightarrow\\) \\Longleftarrow \\(\\Longleftarrow\\) \\Longrightarrow \\(\\Longrightarrow\\) \\leftrightarrow \\(\\leftrightarrow\\) \\longleftrightarrow \\(\\longleftrightarrow\\) \\Leftrightarrow \\(\\Leftrightarrow\\) \\Longleftrightarrow \\(\\Longleftrightarrow\\) \\leftharpoonup \\(\\leftharpoonup\\) \\rightharpoonup \\(\\rightharpoonup\\) \\leftharpoondown \\(\\leftharpoondown\\) \\rightharpoondown \\(\\rightharpoondown\\) \\rightleftharpoons \\(\\rightleftharpoons\\) \\S \\(\\S\\) \\nwarrow \\(\\nwarrow\\) \\nearrow \\(\\nearrow\\) \\swarrow \\(\\swarrow\\) \\searrow \\(\\searrow\\) \\triangle \\(\\triangle\\) \\box \\(\\Box\\) \\diamond \\(\\diamond\\) \\diamondsuit \\(\\diamondsuit\\) \\heartsuit \\(\\heartsuit\\) \\clubsuit \\(\\clubsuit\\) \\spadesuit \\(\\spadesuit\\) 数学公式 有时候需要罗列多个公式,可以用eqnarray*标签包围公式代码,在需要转行的地方使用\\\\,每行需要使用2个&来标识对齐位置,两个&...&号之间的是公式间对齐的位置,每行公式后可使用\\tag{...}标签编号 123456$$\\begin{eqnarray}x^n+y^n &=& z^n \\tag{1.4} \\\\x+y &=& z \\tag{1.5}\\end{eqnarray}$$ \\[ \\begin{eqnarray} x^n+y^n &=& z^n \\tag{1.4} \\\\ x+y &=& z \\tag{1.5} \\end{eqnarray} \\] 当想让字母出现在公式下方时使用\\mathop{} 1a = \\mathop{argmax}_aF(a) \\[a = \\mathop{argmax}_aF(a)\\]","categories":[{"name":"Others","slug":"Others","permalink":"https://godway999.github.io/categories/Others/"}],"tags":[{"name":"Mardown","slug":"Mardown","permalink":"https://godway999.github.io/tags/Mardown/"}]},{"title":"Mac本地用Eclipse配置NS3开发环境(完整教程)","slug":"Others3","date":"2019-05-03T13:48:29.000Z","updated":"2019-07-03T02:43:17.384Z","comments":true,"path":"2019/05/03/Others3/","link":"","permalink":"https://godway999.github.io/2019/05/03/Others3/","excerpt":"","text":"前言 这段时间接触了NS3,发现这个框架在计算机网络领域用的还是蛮多的,在本地搭建开发环境的过程中也遇到了不少坑,这里记录一下整个过程。 在终端下编译和运行NS3程序 NS3的下载和编译NS3官网上给的过程已经很详细了,这里简要概述一下。官放一共提供了三种方法:build.py,bake,waf。个人推荐使用waf编译整个项目(官方文件中自带waf编译器),因为前两种涉及到好多python环境的依赖,我觉得容易出问题。 在我的Mac上由于使用clang++,一定要加上--disable-werror,如果需要搭建python3的开发环境,需要指明python3具体位置。 123cd (本地存放位置)/ns-allinone-3.29/ns-3.29/./waf --enable-test --build-profile=debug --python=/usr/local/bin/python3 --with-python=python3 --disable-werror configure./waf build 经过一段时间的编译之后,在当前目录下运行一个官方例程scratch-simulator,如果一切顺利可以看到程序输出一行Scratch Simulator 1./waf --run scratch/scratch-simulator 在Eclipse上配置NS3开发环境 作为一个新手,如果没有一个友好的开发环境,很容易就进入从入门到放弃的阶段。NS3最让我不能接受的是必须用官方给的waf编译代码,我一开始尝试在Xcode搭建环境,然而Xcode好像对于使用外部编译器的支持不是很好,最终我还是转到在Eclipse上搭建开发环境。 在Eclipse上新建项目 按如下顺序File -> New -> C/C++ Project,创建C++项目 着重强调!!!NS3的代码必须放到(本地存放位置)/ns-allinone-3.29/ns-3.29/scratch/文件夹下才能被正确编译执行所以工程位置放在(本地存放位置)/ns-allinone-3.29/ns-3.29/,这里工程名字自己定,我这里取名为NS3,右侧的编译器随便选一个,之后点finish完成。 编译NS3项目 如果前一步没遇到问题,现在左侧的工程目录应该基本长这样子,以后就直接在scratch目录下新创xxx.cc文件就好了。 之后这里右键NS3文件夹,进入工程属性面板。右侧点击C/C++ Build然后照我的样子配置两处。 编译器类型记得选为外部编译器,编译器选为当前目录下的waf编译器,编译结果放在当前目录下的build文件夹中 之后进入到(本地存放位置)/ns-allinone-3.29/ns-3.29/进行configure操作,如果之前已经configure过了可以跳过该步骤。 12cd (本地存放位置)/ns-allinone-3.29/ns-3.29/./waf --enable-test --build-profile=debug --python=/usr/local/bin/python3 --with-python=python3 --disable-werror configure configure过了之后点击Eclipse左上角的Build按钮就可以编译整个NS3工程了 配置Eclipse使用外部编译器waf 构建完了整个NS3工程之后,我们后续怎么运行我们自己写的代码呢?这时候需要配置使用外部编译器waf。 在Eclipse顶部按如下顺序Run -> Extern Tools -> Extern Tools Configurations 左侧右键点击新建一个编译器。 我这里将这个外部编译器取名为ns3-waf,其余两个和之前一样,参数这里填写--run \"${string_prompt}\" 这里点掉这个Build before launch选项 之后点击Eclipse上方红色方框内的按钮 然后会弹出一个选项框让填写你要编译的文件的名称,注意这里不用加.cc后缀,比如我要编译运行scratch文件夹下的scratch-simulator.cc,就直接填写scratch-simulator或scratch/scratch-simulator。如果你的自己写的文件之前已经build过了,就不需要再加文件目录scratch/,直接填写文件名就好。 下方显示运行结果 配置NS工程路径 此时虽然能够运行自己写的NS3代码了,但是代码中却还有一堆烦人的下波浪线〰️,并且头文件的引用等都是查询不到的,这里就需要配置一下NS3工程路径和环境。 和之前一样,首先进入属性面板。然后找到图中所示的配置目录 这一步将(本地存放位置)/ns-allinone-3.29/ns-3.29/build/ns3/下所有工程头文件包含了进来。 然后构建会花费一小会时间,之后可以在左侧NS3/includes/下看到新生成了一个NS3/build/ns3文件,然后代码中的波浪线就全部消失了 配置完成","categories":[{"name":"Others","slug":"Others","permalink":"https://godway999.github.io/categories/Others/"}],"tags":[]},{"title":"数据库原理——第七章:数据库设计","slug":"Database7","date":"2019-05-03T11:42:57.000Z","updated":"2019-06-19T06:16:40.542Z","comments":true,"path":"2019/05/03/Database7/","link":"","permalink":"https://godway999.github.io/2019/05/03/Database7/","excerpt":"","text":"参考书目《数据库系统概论(第5版)》 数据库设计概述 数据库设计的一般定义: 数据库设计是指对于一个给定的应用环境,构造(设计)优化的数据库逻辑模式和物理结构,并据此建立数据库及其应用系统,使之能够有效地存储和管理数据,满足各种用户的应用需求,包括信息管理要求和数据操作要求 数据库设计的6个阶段: 需求分析阶段。 概念结构设计阶段。 逻辑结构设计阶段。 物理结构设计阶段。 数据库实施阶段。 数据库运行和维护阶段。 需求分析和概念结构设计可以独立于任何数据库管理系统进行,逻辑结构设计和物理结构设计与选用的数据库管理系统密切相关 需求分析 简单的说就是用户缺少计算机知识,我们需要通过与他们的交流来获得我们构建数据库所必要的信息以及用户的需求 通过调查明确用户的各种需求: (1)信息要求:用户需要从数据库中获得信息的内容与实质 (2)数据要求:数据库需要存储哪些数据 (3)处理要求:用户要完成的数据处理功能 (4)安全性与完整性要求。 数据字典 结构: 数据项。数据的最小组成单元 数据结构。反应数据之间的组合关系 数据流。是数据结构在系统内传输的路径 数据存储。是数据结构停留或保存的地方,也是数据流的来源和去向之一 处理过程。具体处理逻辑一般用判定表或判定树来描述 概念结构设计 将需求分析得到的用户需求抽象为信息结构(即概念模型)的过程就是概念结构设计 需要根据数据库关系理论对数据库结构进行优化,如模式分解 需要注意的是并不是规范化程度越高的关系就越优 E-R模型 E-R图提供了表示实体型、属性和联系的方法: (1)实体型用矩形表示,矩形框内写明实体名 (2)属性用椭圆表示,并用无向边将其与相应的实体型连接起来 (3)联系用菱形表示,菱形框内写明联系名,并用无向边分别与有关实体型连接起来,同时在无向边旁标上联系的类型(1:1、1:n或m:n) 逻辑结构设计 逻辑结构设计的任务就是把概念结构设计阶段设计好的基本E-R图转化为与选用数据库管理系统产品所支持的数据模型相符合的逻辑结构 E-R图向关系魔性的转换 一个实体型转化为一个关系模式 一个1:1联系可以转化为一个独立的关系模式,也可以与任意端的关系模式合并 若与某一端合并,则需要在该关系模式的属性中加入另一关系模式的码和联系本身的属性 一个1:n联系可以转化为一个独立的关系模式,也可以与n端的关系模式合并 一个m:n联系转化为一个关系模式 与该关系模式相连的各实体的码以及联系本身的属性均转化为关系的属性,各实体的码组成关系的码或关系码的一部分 三个或三个以上实体间的多元联系可以转化为一个关系模式 具有相同码的关系模式可以合并 物理结构设计 为一个给定的逻辑数据模型选取一个最合适应用要求的物理结构的过程,就是数据库的物理设计 数据库的物理设计通常分为两步: 确定数据库的物理结构,在关系型数据库中主要指存取方法和存储结构 对物理结构进行评价,评价的重点是时间和空间效率 数据库管理系统一般提供多种存取方法。常用的存取方法为索引方法和聚簇方法 B+树索引和hash索引是数据库中经典的存取方法 数据库的实施与维护 数据库的维护工作: 数据库的转储和恢复 数据库的安全性、完整性控制 数据库性能的监督、分析和改造 数据库的重组织与重构造","categories":[{"name":"数据库原理","slug":"数据库原理","permalink":"https://godway999.github.io/categories/数据库原理/"}],"tags":[]},{"title":"数据库原理——第六章:关系数据库理论","slug":"Database6","date":"2019-04-27T11:42:54.000Z","updated":"2019-06-19T00:48:23.004Z","comments":true,"path":"2019/04/27/Database6/","link":"","permalink":"https://godway999.github.io/2019/04/27/Database6/","excerpt":"","text":"参考书目《数据库系统概论(第5版)》 问题的提出 针对一个具体的问题,应该如何构建一个适用于它的数据库模式,即应该构建几个关系模式,每个关系由哪些属性组成等。这是数据库设计的问题,确切地讲是关系数据库逻辑设计问题(如何构造合适的数据模式)。 数据依赖是一个关系内部属性与属性之间的约束关系,这种约束关系是通过属性值的相等与否体现出来的数据间相关联系。 一个好的关系模式不会发生插入异常、删除异常和更新异常,数据冗余尽可能的少。 规范化 函数依赖 定义:若属性组\\(X\\)能唯一确定属性组\\(Y\\),则称\\(X\\)函数确定\\(Y\\)或\\(Y\\)函数依赖\\(X\\),记作\\(X \\rightarrow Y\\)。 \\(X \\rightarrow Y\\),但\\(Y \\nsubseteq X\\),则称\\(X \\rightarrow Y\\)是非平凡的函数依赖。\\(X\\)称为这个函数依赖的决定属性组,也称为决定属性。 \\(X \\rightarrow Y\\),但\\(Y \\subseteq X\\),则称\\(X \\rightarrow Y\\)是平凡的函数依赖。对于任一关系模式,平凡函数依赖都是必然成立的,它不反映新的语义。若不特别声明,总是讨论非平凡的函数依赖。 若\\(X \\rightarrow Y\\),\\(Y \\rightarrow X\\),则记作\\(X \\leftarrow \\rightarrow Y\\)(即直接函数依赖) 若\\(Y\\)不函数依赖于\\(X\\),则记作\\(X \\nrightarrow Y\\) 定义:在\\(R(U)\\)中,如果\\(X \\rightarrow Y\\),并且对于\\(X\\)的任何一个真子集\\(X'\\),都有\\(X' \\nrightarrow Y\\),则称\\(Y\\)对\\(X\\)完全函数依赖,记作\\(X \\stackrel{F}{\\rightarrow} Y\\) 若\\(X \\rightarrow Y\\),但\\(Y\\)不完全函数依赖于\\(X\\),则称Y对X部分函数依赖,记作\\(X \\stackrel{P}{\\rightarrow} Y\\),等价于在完全函数依赖中加入冗余属性使之变成部分函数依赖 定义:在\\(R(U)\\)中,如果\\(X \\rightarrow Y (Y \\nsubseteq X)\\),\\(Y \\nrightarrow X\\),\\(Y \\rightarrow Z\\),\\(Z \\nsubseteq Y\\),则称\\(Z\\)对\\(X\\)传递函数依赖,记作\\(X \\stackrel{传递}{\\rightarrow} Y\\) 码 定义:设\\(K\\)为\\(R< U,F >\\)中的属性或属性组合,若\\(K \\stackrel{F}{\\rightarrow} U\\),则\\(K\\)为\\(R\\)的候选码 如果\\(K \\stackrel{P}{\\rightarrow} U\\),则\\(K\\)称为超码。候选码是最小的超码,即\\(K\\)的任何一个真子集都不是候选码 包含在任何一个候选码中的属性称为主属性,不包含在任何候选码中的属性称为非主属性,整个属性组都是码称为全码 定义:关系模式\\(R\\)中属性或属性组合\\(X\\)并非\\(R\\)的码,但\\(X\\)是另一个关系模式的码,则称\\(X\\)是\\(R\\)的外码 范式 关系数据库中的关系是要满足一定要求的,满足不同程度要求的为不同范式 各种范式之间的关系有: \\[5NF \\subset 4NF \\subset BCNF \\subset 3NF \\subset 2NF \\subset 1NF\\] 一个低一级范式的关系模式通过模式分解(schema decomposition)可以转化为若干高一级范式的关系模式的集合,这叫做规范化(normalization) 1NF 每个分量(属性)必须是不可分的数据项 2NF 相比于1NF,消除了非主属性对码的部分函数依赖 定义:设关系模式\\(R< U,F >\\), 若\\(R \\in 1NF\\),且每个非主属性完全函数依赖于任何一个候选码,则\\(R \\in 2NF\\) 一个关系模式R若不属于2NF,可能会产生:插入异常、删除异常、修改复杂 3NF 相比于2NF,消除了非主属性对码的传递函数依赖 定义:设关系模式\\(R< U,F >\\),若\\(R \\in 3NF\\),则每个非主属性既不传递依赖于码,也不部分依赖于码,也就是说,若R属于3NF则必有R属于2NF BCNF 相比于3NF,消除了主属性对码的部分和传递函数依赖 定义:设关系模式\\(R< U,F >\\),若每个决定因素都包含码(候选码),则\\(R \\in BCNF\\) 满足BCNF的关系模式的性值: 所有非主属性对每一个码都是完全函数依赖 所有主属性对每一个不包含它的码也是完全函数依赖 没有任何属性完全函数依赖于非码的任何一组属性 多值依赖 &&& 4NF 相比于BCNF,消除了非平凡且非函数依赖的多值依赖 规范化小结 规范化的基本思想是逐步消除数据依赖中不合适的部分 o1=>operation: 1NF i12=>inputoutput: 消除非主属性对码的部分函数依赖 o2=>operation: 2NF i23=>inputoutput: 消除非主属性对码的传递函数依赖 o3=>operation: 3NF i3b=>inputoutput: 消除主属性对码的部分和传递函数依赖 ob=>operation: BCNF ib4=>inputoutput: 消除非平凡且非函数依赖的多值依赖 o4=>operation: 4NF o1->i12->o2->i23->o3->i3b->ob->ib4->o4{\"scale\":1,\"line-width\":2,\"line-length\":50,\"text-margin\":10,\"font-size\":12} var code = document.getElementById(\"flowchart-0-code\").value; var options = JSON.parse(decodeURIComponent(document.getElementById(\"flowchart-0-options\").value)); var diagram = flowchart.parse(code); diagram.drawSVG(\"flowchart-0\", options);","categories":[{"name":"数据库原理","slug":"数据库原理","permalink":"https://godway999.github.io/categories/数据库原理/"}],"tags":[]},{"title":"数据库原理——第五章:数据库完整性","slug":"Database5","date":"2019-04-26T11:42:51.000Z","updated":"2019-06-18T13:10:38.750Z","comments":true,"path":"2019/04/26/Database5/","link":"","permalink":"https://godway999.github.io/2019/04/26/Database5/","excerpt":"","text":"参考书目《数据库系统概论(第5版)》 数据库的完整性是指数据的正确性和相容性 数据的正确性是指数据是符合现实世界语义、反映当前实际状况的(实体完整性和用户定义的完整性) 数据的相容性是指数据库同一对象在不同关系表中的数据是符合逻辑的(参照完整性) 实体完整性 关系模式的实体完整性在CREATE TABLE中用PRIMARY KEY定义 单属性构成的码有两种说明方式:列级约束条件、表级约束条件 多属性构成的码只有一种说明方式:表级约束 实体完整性检查和违约处理: 检验主码值是否唯一,如果不唯一则拒绝插入或修改 检查主码的各个属性是否为空,只要有一个为空就拒绝插入或修改 12345例:CREATE TABLE XXX( Sno CHAR(20) PRIMARY KEY, /*单属性可以在列级定义主码*/ PRIMARY KEY(Sno,Cno,...), /*多属性只能在表级定义主码*/); 参照完整性 关系模式的参照完整性在CREATE TABLE中用FORIEGN KEY短语定义哪些属性为外码,用REFERENCES指明这些外码参照哪些表的主码 12345例:CREATE TABLE XXX( Cno CHAR(20), FOREIGN KEY(Cno) REFERENCES Course(Cno), /*在表级定义参照完整性*/); 可能破坏参照完整性的情况及违约处理: 被参照表<=>参照表 违约处理 可能破坏参照完整性<-插入元组 拒绝 可能破坏参照完整性<-修改外码值 拒绝 删除元组->可能破坏参照完整性 拒绝/级联删除/设为空值 修改主码值->可能破坏参照完整性 拒绝/级联删除/设为空值 用户定义的完整性 用户定义的完整性就是针对某一具体应用的数据必须满足的语义要求 在CREATE TABLE中定义属性的同时,可以根据应用的要求定义属性上的约束条件,即属性值的限制,包括: 列值非空(NOT NULL) 值唯一(UNIQUE) 检查列值是否满足一个条件表达式(CHECK短语) 与属性上约束条件的定义类似,在CREATE TABLE语句中可以用CHECK短语定义元组上的约束条件,即元组级的限制。 12345678例:CREATE TABLE Student( Sno CHAR(9) UNIQUE NOT NULL, /*要求Sno值唯一且不能为空*/ Sname CHAR(8) NOT NULL, Sage int CHECK(Sage >= 15 AND Sage <= 50) /*列级CHECK短语*/ Ssex CHAR(2), CHECK(Ssex='女' OR Sname NOT LIKE'Ms.%') /*定义了元组中两个属性值之间的约束*/); 完整性约束命名子句 用完整性约束命名子句CONSTRAINT,用来对完整性约束条件命名,从而便于管理完整性约束条件 1CONSTRAINT <完整性约束条件名> <完整性约束条件> 其中包括NOT NULL、UNIQUE、PRIMARY KEY、FOREIGN KEY、CHECK等 12345678910例:CREATE TABLE Student( Sno NUMERIC(6), Sname CHAR(20), Sage NUMERIC(3) NOT NULL, CONSTRAINT StudentKey PRIMARY KEY(Sno), CONSTRAINT SnameKey FOREIGN KEY(Sname) REFERENCES Course(Sname), CONSTRAINT C1 CHECK(Sno BETWEEN 90000 AND 99999), CONSTRAINT C2 UNIQUE(Sname)); 修改表中的完整性限制,可以先删除原来的约束条件,再增加新的约束条件 12ALTER TABLE <表名> DROP CONSTRAINT <完整性约束条件名>ALTER TABLE <表名> ADD CONSTRAINT <完整性约束条件名> <完整性约束条件> 触发器 触发器(trigger)是用户定义在关系表上的一类由事件驱动的特殊过程 触发器类似于约束,但是比约束更加灵活,可以实施更为复杂的检查和操作,具有更精细和更强大的数据控制能力 1234567/*触发器一般格式*/CREATE TRIGGER <触发器名>[BEFORE|AFTER] [INSERT|DELETE|UPDATE] ON <表名>FOR EACH [ROW|STATEMENT]BEGIN <执行语句列表>END 例如:建立触发器t1,当插入学生的年龄小于18岁时进行报错提示 123456789101112DELIMITER $ /*告诉mysql语句的结尾符号换成以$结束*/CREATE TRIGGER t1BEFORE INSERT ON StudentFOR EACH ROWBEGIN DECLARE msg VARCHAR(200); IF NEW.Sage < 18 THEN SET msg = CONCAT('输入的年龄值: ',NEW.Sage,' 为无效的年龄,请确保学生年龄大于18岁'); SIGNAL SQLSTATE 'HY000' SET MESSAGE_TEXT = msg; END IF;END$DELIMITER ; /*将结尾符号换回以;结束*/ MySQL 中定义了NEW和OLD,用来表示触发器的所在表中,触发了触发器的那一行数据,来引用触发器中发生变化的记录内容,具体地: 在INSERT型触发器中,NEW用来表示将要(BEFORE)或已经(AFTER)插入的新数据 在UPDATE型触发器中,OLD用来表示将要或已经被修改的原数据,NEW用来表示将要或已经修改为的新数据 在DELETE型触发器中,OLD用来表示将要或已经被删除的原数据 另外OLD是只读的,而NEW则可以在触发器中赋值,这样不会再次触发触发器,导致递归循环调用","categories":[{"name":"数据库原理","slug":"数据库原理","permalink":"https://godway999.github.io/categories/数据库原理/"}],"tags":[]},{"title":"数据库原理——第四章:数据库安全性","slug":"Database4","date":"2019-04-25T11:42:48.000Z","updated":"2019-06-18T13:00:32.028Z","comments":true,"path":"2019/04/25/Database4/","link":"","permalink":"https://godway999.github.io/2019/04/25/Database4/","excerpt":"","text":"参考书目《数据库系统概论(第5版)》 数据库安全性概述 数据库安全标准:TCSEC和CC TCSEC/TDI安全级别划分(从上到下安全级别逐渐降低) 安全级别 定义 A1 验证设计 B3 安全域 B2 结构化保护 B1 标记安全保护 C2 受控的存取保护 C1 自主安全保护 D 最小保护 C1级:只提供了非常初级的自主安全保护,能够实现对用户和数据的分离,进行自助存取控制(DAC) B1级:对系统的数据加以标记,并对标记的主体和客体实施强制存取控制(MAC)以及审计等安全机制。B1级别的产品才被认为是真正意义上的安全产品 数据库安全性控制 用户身份鉴别 这是数据库管理系统提供的最外层安全保护机制 静态口令鉴别 动态口令鉴别 生物特征鉴别 智能卡鉴别 存取控制 存取控制机制主要包括定义用户权限和合法权限检查,二者一起组成了数据库管理系统的存取控制子系统 自主存取控制:用户对于不同的数据库对象拥有不同的存取权限,不同用户对同一对象也有不同权限,而且用户可以将其拥有的权限转授给其他用户。因此自主存取控制非常灵活 强制存取控制:每个数据库对象被标以一定的密级,每一个用户也被授予某一个级别的许可证。对于任意一个对象,只有具有合法许可证的用户才可以存取。因此强制存取控制相对比较严格 自主存取控制方法 用户权限由两个要素组成:数据库对象、操作类型 定义用户的存取权限称为授权 ------后续语句实现基于MySQL------ 创建用户 12CREATE USER <用户名>@<用户登陆主机> [IDENTIFIED BY <密码>];CREATE USER <用户名>; /*可以在本地无密码登录的账户*/ 用户登录主机若不填写则默认为localhost,若要允许远程登陆,则localhost可以替换为相应的主机ip,或者直接替换为:%(表示任何一台主机都可以远程登陆) 新用户的密码可以选择不创建 修改用户密码 12ALTER USER <用户名>@<用户登陆主机> IDENTIFIED BY <新密码>SET PASSWORD FOR <用户名>@<用户登陆主机> = PASSWORD('新密码') /*创建新密码*/ 删除用户 1DROP USER [IF EXIST] <用户名>@<用户登陆主机> 给用户授权 1GRANT <权限>(属性名),... ON <数据库名>.<数据库表名>,... TO <用户名>@<用户登陆主机>,... [WITH GRANT OPTION] 如果指定了WITH GRANT OPTION子句,则获得某种权限的用户还可以把这种权限再授予其他用户(传播权限) 对于(属性名),如UPDATE(Sno)表示对于Sno这个属性具有更新的权限,若不填则默认为所有属性 如果想给新用户所有的权限,可以直接使用ALL PRIVILEGES 收回授权 1REVOKE <权限>(属性名),... ON <数据库名>.<数据库表名>,... FROM <用户名>@<用户登陆主机>,... 数据库角色 MySQL 8.0 为了用户权限管理更容易,提供了一个角色管理的新功能 数据库角色是被命名的一组与数据库操作相关的权限,角色是权限的集合。如果用户被授予角色权限,则该用户拥有该角色的权限,从而简化授权过程 MySQL 8.0 提供的角色管理功能如下: 12345678CREATE ROLE 角色创建DROP ROLE 角色删除GRANT 为用户和角色分配权限REVOKE 为用户和角色撤销权限SHOW GRANTS 显示用户和角色的权限SET DEFAULT ROLE 指定哪些帐户角色默认处于活动状态SET ROLE 更改当前会话中的活动角色CURRENT_ROLE() 显示当前会话中的活动角色 创建用户、分配权限、回收权限、验证 创建用户 1CREATE USER wsy@'%' IDENTIFIED BY '111111'; 分配权限 1GRANT INSERT,UPDATE,ALTER ON test.* TO wsy@'%'; 回收权限 1REVOKE UPDATE ON test.* FROM wsy@'%'; 验证 1234567/*使用用户wsy登录Mysql之后*/SELECT user();USE test;DESC P;INSERT INTO P VALUES ('P7', '螺母', '绿', 32);SELECT * FROM P WHERE PNO='P1'UPDATE P SET P=P+10 WHERE COLOR='红'; 结果如下 创建角色、分配权限、回收权限、验证 创建角色 1CREATE ROLE visitor; 分配权限 1GRANT SELECT ON test.* TO visitor; 回收权限 1REVOKE SELECT ON test.* FROM visitor; 验证 12345/*root账户下,分配visitor角色给wsy*/GRANT visitor TO wsy;/*使用用户wsy登录Mysql之后*/USE test; 强制存取控制方法 自助存取控制可能不安全的根本原因在于:仅仅通过对数据的存取控制权限来进行安全控制,而数据本身并无安全性标记 在强制存取控制中,全部实体被分为主体和客体两大类。主体是系统中的活动实体,客体是系统中的被动实体,受主体操控 数据库管理系统为每个实例指派一个敏感度标记,敏感度标记可被分为:TS >= S >= C >= P 主体的敏感度标记称为许可证级别,客体的敏感度标记称为密级 判定规则: 仅当主体的许可证级别大于或等于客体的密级是,该主体才能读取相应的客体 仅当主体的许可证级别小于或等于客体的密级是,该主体才能写相应的客体 视图 通过视图机制把要保密的数据对无权存取的用户隐藏起来 审计 审计功能把用户对数据库的所有操作自动记录下来放入审计日志中。管理人员可利用审计日志监控数据库的各种行为,重现操作过程,找出非法存取数据的人、时间和内容等 ------后续语句实现基于MySQL8.0------ 开启审计功能 设置变量 12345678/*打开审计开关*/set global general_log = on;set global general_log_file = '/var/lib/mysql/operation.log';set global log_timestamps = SYSTEM;/*查看审计状态*/show global variables like 'log_timestamps';show global variables like '%general%'; 设置审计权限 创建用于存放连接日志的数据库和表 123456789create database auditlog;create table auditlog.t_audit(id int not null auto_increment,thread_id int not null,login_time timestamp,localname varchar(50) default null,matchname varchar(50) default null,primary key (id))ENGINE=InnoDB default charset=utf8 comment '审计用户登录信息'; 授权某个用户拥有对审计表的select和insert权限 12345/*给出对所有用户授权的语句(拼结授权语句)*/SELECT concat("GRANT SELECT,INSERT ON auditlog.t_audit to '",user,"'@'",host,"';") FROM mysql.user;/*授权用户wsy*/GRANT SELECT,INSERT ON auditlog.* to wsy@'%'; 设置init_connect参数 1SET GLOBAL init_connect='INSERT INTO auditlog.t_audit(id,thread_id,login_time,localname,matchname) VALUES(null,connection_id(),now(),user(),current_user());'; 普通用户登录,执行操作 查看登录记录 1SELECT * FROM t_audit WHERE matchname='wsy@%'; 执行插入操作 1INSERT INTO P VALUES ('P8', '丝轴', '银', 12); 之后查看日志记录cat /var/lib/mysql/operation.log 可以看到insert操作已经被记录下来 查照操作者 12/*使用root用户*/SELECT * FROM t_audit; 可以看到用户wsy在2019-05-07 19:10:56登录,并在2019-05-07 19:11:11进行了insert操作。","categories":[{"name":"数据库原理","slug":"数据库原理","permalink":"https://godway999.github.io/categories/数据库原理/"}],"tags":[]},{"title":"数据库原理——第三章:关系数据库标准语言SQL","slug":"Database3","date":"2019-04-24T11:42:45.000Z","updated":"2020-03-10T14:08:04.101Z","comments":true,"path":"2019/04/24/Database3/","link":"","permalink":"https://godway999.github.io/2019/04/24/Database3/","excerpt":"","text":"参考书目《数据库系统概论(第5版)》 SQL概述 SQL 结构化查询语言(Structured Query Language) 的主要特点: 综合统一 高度非过程化 面向集合的操作方式 以同一种语法结构提供多种使用方式 语言简洁,易学易用 SQL的动词 SQL功能 动词 数据查询 SELECT 数据定义 CREATE,DROP,ALTER 数据操作 INSERT,UPDATE,DELETE 数据控制 GRANT,REVOKE 基本表的定义、删除与修改 1.定义基本表 12345678CREATE TABLE <表名> (<属性名> <数据类型> [列级完整性约束],<属性名> <数据类型> [列级完整性约束],...[表级完整性约束],[表级完整性约束],...)[CHARSET=utf8]; 2.数据类型 数据类型 含义 CHAR(n) 长度为n的定长字符串 VARCHAR(n) 最大长度为n的变长字符串 TINYBLOB/BLOB/LONGBLOB 不同大小的二进制形式的文本数据 TINYTEXT/TEXT/LONGTEXT 不同大小的文本数据 TINTINT/SMALLINT/BIGINT 不同字节大小的整数 FLOAT/DOUBLE 单/双精度浮点数 DATE 日期值(YYYY-MM-DD) TIME 时间值(HH:MM:SS) YEAR 年份值(YYYY) DATETIME 混合日期和时间值 TIMESTAMP 混合日期和时间值,时间戳 3.修改基本表 12345678910111213141516#增加列(属性)ALTER TABLE <表名> ADD <新属性名> <数据类型> [列级完整性约束];#删除列(属性)ALTER TABLE <表名> DROP <选择的属性名>;#添加表级完整性约束条件ALTER TABLE <表名> ADD [列级完整性约束];#删除键约束ALTER TABLE <表名> DROP PRIMARY KEY;ALTER TABLE <表名> DROP FOREIGN KEY <键名>;/*可以通过使用SHOW CREATE TABLE <表名>;来查询外键的键名*/#修改属性的数据类型ALTER TABLE <表名> MODIFY <选择的属性名> <新数据类型>; 4.删除基本表 1DROP TABLE [IF EXIST] <表名>; 索引的建立与删除 1.建立索引 12/*若属性为字符串等类型,可以加上length表示根据前多个字符作为索引,从而节省建立索引的开销*/CREATE [UNIQUE|FULLTEXT|SPATIAL] INDEX <索引名> ON <表名>(属性名[(length)],...); 2.删除索引 12ALTER TABLE <表名> DROP INDEX <索引名>;DROP INDEX <索引名> ON <表名>; 3.查看索引 1SHOW INDEX FROM [<数据库名>.]<表名>; 数据字典 数据字典是关系数据库系统内部的一组系统表,它记录了数据库中所有的定义信息,包括关系模式定义、视图定义、索引定义、完整性约束定义、各类用户对数据库的操作权限、统计信息等。 在进行查询优化和查询处理时,数据字典中的信息是其重要的依据。 数据的查询 单表查询 1.选择表中的的若干列 1SELECT [ALL|DISTINCT] <目标属性表达式>,... FROM <表名或视图名>; SECLECT默认使用ALL,表示将结果全部显示。但在有些情况下,投影出来的结果会出现重复行,此时可以用DISTINCT去掉重复行 可以简单的写为目标属性名 如果属性列的显示顺序与在基本表中的顺序相同,也可简单的将指定为 * 不仅可以是表中的属性列,也可以是算数表达式、字符串常量、函数等。 用户可以通过指定别名来改变查询结果的列标题 12345678910#查询指定列或全部列SELECT Sname,Sno FROM Student;SELECT * FROM Student;#使用算术表达式、字符串常量和函数SELECT Sname,‘Year of Birth’,2019-Sage,LOWER(Sdept) FROM Student;#使用别名SELECT Sname NAME,‘Year of Birth’ BIRTH,2019-Sage BIRTHDAY,LOWER(Sdept) DEPARTMENT FROM Student; 2.查询满足条件的元组 1SELECT <目标属性表达式>,... FROM <表名或视图名> WHERE <条件表达式>; 查询满足指定条件的元组可以通过WHERE子句实现。例子如下 123456789101112131415161718(1)比较大小SELECT Sname FROM Student WHERE Sdept='CS';SELECT DISTINCT Sno FROM SC WHERE Grade<60;(2)确定范围SELECT Sname,Sage FROM Student WHERE Sage [NOT] BETWEEN 20 AND 23;(3)确定集合(谓词IN用来查找属性值属于指定集合的元组)SELECT Sname FROM Student WHERE Sdept IN ('CS','MA','EE');(4)字符匹配SELECT * FROM Student WHERE Sname LIKE '刘%';(5)涉及空值的查询SELECT Sno,Cno FROM SC WHERE Grade IS NULL; /*分数值为空的对应属性*/(6)多重条件查询SELECT Sname FROM Student WHERE Sdept='CS' AND Sage<20; 谓词LIKE用来进行字符串的匹配,一般格式如下 1[NOT] LIKE '<匹配串>' [ESCAPE '\\'] ESCAPE '\\' 表示''为换码符,用于转义 % 和 _ 可以是一个完整的字符串,也可以含有通配符 % 和 _ ,其中: %(百分号)代表任意长度的字符串。如a%b表示以a开头以b结尾的任意长度的字符串 _(下划线)代表任意单个字符,类似于占位符。如a_b表示以a开头以b结尾长度为3的字符串 注:WHERE子句常用的查询条件表如下 查询条件 谓词 比较 =,>,<,>=,<=,!=,<>,!>,!< ; NOT+上述比较运算符 确定范围 BETWEEN AND, NOT BETWEEN AND 确定集合 IN, NOT IN 字符匹配 LIKE, NOT LIKE 空值 IS NULL, IS NOT NULL 多重条件(逻辑运算) AND, OR, NOT 3.ORDER BY子句 可以用ORDER BY子句对查询结果按照一个或多个属性的升序(ASC)或降序(DESC)排列,默认值为升序 用法为ORDER BY <属性名> ASC|DESC 12#例SELECT Sno,Grade FROM SC WHERE Cno='3' ORDER BY Grade DESC; 4.聚集函数 聚集函数遇到空值时,除了COUNT(*)外,都跳过空值而只处理非空值 WHERE子句中是不能用聚集函数作为条件表达式的。聚集函数只能用于SELECT子句和GROUP BY中的HAVING子句 函数名 作用 COUNT(*) 统计元组个数 COUNT([ALL/DISTINCT] ) 统计一列中值的个数 SUM([ALL/DISTINCT] ) 计算一列值的总和(此列必须是数值型) AVG([ALL/DISTINCT] ) 计算一列值的平均值(此列必须是数值型) MAX([ALL/DISTINCT] ) 求一列值中的最大值 MIN([ALL/DISTINCT] ) 求一列值中的最小值 5.GROUP BY子句 GROUP BY子句将查询结果按某一列或多列的值分组,值相等的为一组。 对查询结果分组的目的是为了细化聚集函数的作用对象。分组后聚集函数将作用于每组,即每一组都有一个函数值。 WHERE子句与HAVING短语的区别在于作用对象不同。WHERE子句作用于基本表或视图,从中选择满足条件的元组;HAVING短语作用于组,从中选择满足条件的组 1234#例SELECT Cno, COUNT(Sno) FROM SC GROUP BY Cno;SELECT Sno FROM SC GROUP BY Sno HAVING COUNT(*) > 3;SELECT Sno, AVG(Grade) FROM SC GROUP BY Sno HAVING AVG(Grade) >= 90; 连接查询 1.等值与非等值连接查询 当连接运算符为=时,称为等值连接。使用其他运算符称为非等值连接。 注意:若选择的属性列在两个表中是唯一的,则可以省去表名前缀;若不唯一,则引用时必须加上表名前缀。 123456#等值连接SELECT Student.*, SC.* FROM Student, SC WHERE Student.Sno=SC.Sno;#非等值连接SELECT Student.Sno, Sname FROM Student, SC WHEREStudent.Sno=SC.Sno AND SC.Cno='2' AND SC.Grade>90; 2.自身连接 连接操作不仅可以在两个表之间进行,也可以是一个表与其自身进行连接,称为表的自身连接。 123#例SELECT FIRST.Cno, SECOND.Cpno FROM Course FIRST, Course SECOND WHERE FIRST.Cpno=SECOND.Cno;/*为了区分自身的两个表而给这两个表分别取了别名FIRST和SECOND*/ 3.外连接 两个表进行连接时,若其中一个表没有相关的元组信息,则按普通的两表连接则会省去某些元组,若想保留则可以使用外连接。 12#例SELECT Student.Sno, Sname, Ssex, Sage, Sdept, Cno, Grade FROM Student LEFT OUTER JOIN SC ON (Student.Sno=SC.Sno); 4.多表连接 还可以进行两个表以上的连接,称为多表连接。 12#例SELECT Student.Sno, Sname, Cname, Grade FROM Student, SC, Course WHERE Student.Sno=SC.Sno AND SC.Cno=Course.Cno; 嵌套查询 一个SELECT-FROM-WHERE语句称为一个查询块。将一个查询块嵌套在另一个查询块的WHERE子句或HAVING短语的条件中的查询称为嵌套查询 子查询的SELECT语句不能使用ORDER BY子句,ORDER BY子句只能对最终的查询结果排序 子查询的查询条件不依赖于父查询,称为不相关子查询,否则称为相关子查询 1.带有IN谓词的子查询 1234#查询与Sam在同一个系的学生SELECT Sno, Sname, Sdept FROM Student WHERE Sdept IN ( SELECT Sdept FROM Student WHERE Sname='Sam'); 有些查询可以用连接查询替代,有些是不能替代的 2.带有比较运算符的子查询 1234#查询每个学生超过他自己选修课程平均成绩的课程号(此例为一个相关子查询)SELECT Sno, Cno FROM SC x WHERE Grade >= ( SELECT AVG(Grade) FROM SC y WHERE y.Sno=x.Sno); 3.带有ANY(SOME)或ALL谓词的子查询 子查询返回多值时需要使用ANY和ALL谓词修饰。其中:ANY(表示某个),ALL(表示所有) 123456789#查询非计算机系中比计算机科学系'某个'学生年龄小的学生姓名和年龄SELECT Sname, Sage FROM Student WHERE Sage < ANY ( SELECT Sage FROM Student WHERE Sdept='CS') AND Sdept <> 'CS';#查询非计算机系中比计算机科学系'所有'学生年龄小的学生姓名和年龄SELECT Sname, Sage FROM Student WHERE Sage < ALL ( SELECT Sage FROM Student WHERE Sdept='CS') AND Sdept <> 'CS'; 4.带有EXISTS谓词的子查询 带有EXISTS谓词的子查询不返回任何数据,只产生逻辑结果真值“true”或逻辑假值“false” 1234#查询所有选修了1号课程的学生姓名SELECT Sname FROM Student WHERE EXISTS ( SELECT * FROM SC WHERE Sno=Student.Sno AND Cno='1'); 集合查询 SQL集合操作包括:并操作UNION、交操作INTERSECT、差操作EXCEPT MySql并没有提供对交和差操作的支持,这里就不再举例 1234#查询计算机科学系的学生及年龄不大于19岁的学生SELECT * FROM Student WHERE Sdept='CS' UNION SELECT * FROM Student WHERE Sage<=19; 基于派生表的查询 子查询不仅可以出现在WHERE子句中,也可以出现在FROM子句中,这时子查询生成的临时派生表成为主查询的查询对象 1234#例SELECT Sname FROM Student, (SELECT Sno FROM SC WHERE Cno='1') AS SC1 WHERE Student.Sno=SC1.Sno; SELECT语句的一般格式 一般格式 12345SELECT [ALL|DISTINCT] <目标属性表达式> [别名],...FROM <表名或视图名>,... | (<子查询>) [AS] <别名>[WHERE <>][GROUP BY <属性名1> [HAVING <条件表达式>]][ORDER BY <属性名2> [ASC|DESC]]; 由SELECT语句构成 目标属性表达式的可选格式: * .* COUNT([DISTINCT] *) [.],... 其中,属性名表达式可以是由属性名、作用于属性的聚集函数和常量的任意算数运算(+,-,*,/)组成的运算公式 聚集函数的一般格式 COUNT|SUM|AVG|MAX|MIN( [DISTINCT|ALL] ) WHERE子句的条件表达式的可选格式 \\(\\theta\\) ||[ALL|ANY](子查询) [NOT] BETWEEN ||() AND ||() [NOT] IN (, , ...)|() NOT LIKE 匹配串 IS [NOT] NULL [NOT] EXISTS() AND|OR AND|OR ... 数据的更新 1.插入数据 12345678910111213# 插入元组INSERT INTO <表名>[(<属性名>,...)]VALUES (<对应属性的常量>,...);# 插入子查询结果(建立一个新表)INSERT INTO <新的表名>[(<属性名>,...)]<子查询>;# 例:对每一个系,求学生的平均年龄,并把结果存入新数据表INSERT INTO Dept_age(Sdept, Avg_age) ( SELECT Sdept,AVG(Sage) FROM Student GTOUP BY Sdept); 2.修改数据 123456789101112UPDATE <表名>SET <列名>=<表达式>,...[WHERE <条件>|<子查询>];# 例:将计算机科学系全体学生的成绩置为零UPDATE SCSET Grade=0WHERE Sno IN ( SELECT Sno FROM Student WHERE Sdept='CS'); 3.删除数据 DELETE语句删除的是表中的数据,而不是关于表的定义,表的定义仍在字典中。 123456789101112DELETEFROM <表名>[WHERE <条件>|<子查询>];# 例:删除计算机科学系全体学生的选课记录(SC表)DELETEFROM SCWHERE Sno IN ( SELECT Sno FROM Student WHERE Sdept='CS'); 视图 视图是从一个或几个基本表(或视图)导出的表。它与基本表不同,是一个虚表 1.建立视图 123CREATE VIEW <视图名>[(<属性名>,...)]AS <子查询>[WITH [CASCADED|LOCAL] CHECK OPTION]; 可以是任意的SELECT语句。 WITH [CASCADED|LOCAL] CHECK OPTION表示对视图进行UPDATE、INSERT和DELETE操作时要保证更新、插入或删除的行满足视图定义中的谓词条件(即子查询中的条件表达式)。 组成视图的属性列名或者全部省略或者全部指定,没有第三种选择。但在下列三种情况下必须明确指明: 1. 某个目标列不是单纯的属性名,而是聚集函数或列表达式 2. 多表连接时选出了几个同名列作为视图的字段 3. 需要在视图中为某个列启用新的更合适的名字 关系数据库管理系统执行CREATE VIEW语句的结果,只是把视图的定义存入数据字典,并不执行其中的SELECT语句。 定义:若一个视图是从单个基本表导出的,并且只是去掉了基本表的某些行和某些列,但是保留了主码,则称这类视图为行列子视图。 2.删除视图 1DROP VIEW <视图名> [CASCADE]; 视图删除后视图的定义将从数据字典中删除。如果该视图上还导出了其他视图,则使用CASCADE级联删除语句一起删除。 3.查询视图 从数据字典中取出视图的定义,将其转换成等价的对基本表的操作后再执行,这一转换过程称为视图消解。 12#使用定义的视图IS_Student进行查询年龄小于20岁的学生SELECT Sno, Sage FROM IS_Student WHERE Sage<20; 4.更新视图 对试图的更新最终要转换为对基本表的更新,但不是所有的视图都是可更新的,一般的,行列子集视图是可更新的。 12#例:将信息系学生视图IS_Student中学号为“201215125”的学生姓名改为“lili”UPDATE IS_Student SET Sname='lili' WHERE Sno='201215125'; 5.视图的作用 视图能够简化用户的操作 视图使用户能以多种角度看待同一数据 视图对重构数据库提供了一定程度的逻辑独立性 视图能够对机密数据提供安全保护 适当利用视图可以更清晰地表达查询","categories":[{"name":"数据库原理","slug":"数据库原理","permalink":"https://godway999.github.io/categories/数据库原理/"}],"tags":[]},{"title":"数据库原理——第二章:关系数据库","slug":"Database2","date":"2019-04-22T11:40:06.000Z","updated":"2019-06-18T13:19:32.316Z","comments":true,"path":"2019/04/22/Database2/","link":"","permalink":"https://godway999.github.io/2019/04/22/Database2/","excerpt":"","text":"参考书目《数据库系统概论(第5版)》 关系数据结构及形式化定义 关系数据库是支持关系模型的数据库系统 关系模型是由三部分组成:关系数据结构、关系操作集合、关系完整性约束 关系 域是一组具有相同数据类型的值的集合。属性的取值范围来自某个域 一个域允许的不同取值个数称为这个域的基数 某一属性组的值能唯一的标识一个元组,而其子集不能,则称该属性组为候选码 若一个关系中有多个候选码,则选定其中一个为主码 关系模式的所有属性是这个关系模式的候选码,称为全码 元组:表中的一行 码:表中的某个属性组,它可以唯一确定一个元组 关系模式 关系模式是对关系的描述,关系模式是型,关系是值 定义: 关系的描述称为关系模式。它可以形式化的表示为R(U,D,DOM,F) R为关系名 U为组成该关系的属性名集合 D为U中属性所来自的域 DOM为属性向域的映像集合 F为属性间数据的依赖关系集合 关系操作 常用的关系操作:查询和插入、删除和修改 传统的集合运算:并、差、交、笛卡尔积 专门的关系运算:选择、投影、连接、除运算 结构化查询语言(Structured Query Language, SQL) 关系的完整性 关系模型的完整性规则是对关系的某种约束条件 关系模型中有三类完整性约束:实体完整性、参照完整性、用户定义的完整性 实体完整性 若属性A是基本关系R的主属性,则A不能取空值 参照完整性 设F是基本关系R的一个或一组属性,但不是关系R的码,Ks是基本关系S的主码。如果F与Ks相对应,则称F是R的外码 参照完整性规则就是定义外码与主码之间的引用规则 若属性(或属性组)F是基本关系R的外码,它与基本关系S的主码Ks相对应(基本关系R和S不一定是不同的关系),则对于R中的每个元组在F上的值必须: 或者取空值(F的每个属性值均为空值) 或者等于S中某个元组的主码值 用户定义的完整性 用户定义的完整性就是针对某一具体的关系数据库的约束条件,它反映某一具体应用所涉及的数据必须满足的语义条件 关系代数 传统的集合运算:并、差、交、笛卡尔积 专门的关系运算:选择、投影、连接、除运算 选择(取行) 选择又称为限制。它是在关系R中选择满足给定条件的诸元组 投影(取列) 从R中选择出若干属性列组成新的关系 投影后可能会取消某些元组,因为取消了某些属性列之后可能会出现重复行,应取消相同的行 不能只简单的理解为取列,投影操作还可以获得某属性的所有取值的集合 连接 它从两个关系的笛卡尔积中选取属性间满足一定条件的元组 自然连接是一种特殊的等值连接。它要求两个关系中进行比较的分量必须是同名的属性组,并且在结果中把重复的属性列去掉 在做自然连接时,可能会舍弃某些元组,这些元组被称为悬浮元组 除运算 设关系R处以关系S的结果为关系T,则T包含所有在R但不在S中的属性及其值,且T的元组与S的元组的所有的组合都在R中","categories":[{"name":"数据库原理","slug":"数据库原理","permalink":"https://godway999.github.io/categories/数据库原理/"}],"tags":[]},{"title":"数据库原理——第一章:绪论","slug":"Database1","date":"2019-04-21T03:14:24.000Z","updated":"2019-06-19T00:22:12.309Z","comments":true,"path":"2019/04/21/Database1/","link":"","permalink":"https://godway999.github.io/2019/04/21/Database1/","excerpt":"","text":"参考书目《数据库系统概论(第5版)》 数据库系统概述 数据库的4个基本概念 数据、数据库、数据库管理系统、数据库系统是4个核心概念 数据(data) 数据是数据库中存储的基本对象 数据库(DataBase, DB) 数据库是存放数据的仓库 数据库是长期存储在计算机内、有组织的、可共享的大量数据的集合 数据库数据具有永久存储、有组织和可共享三个基本特点 数据库管理系统(DataBase Management System, DBMS) 数据库管理系统是位于用户与操作系统之间的一层数据管理软件 数据库管理系统和操作系统一样是计算机的基础软件,也是一个大型复杂的软件系统 体系结构为(从低到高):硬件 -> 操作系统 -> 数据库管理系统 -> 应用开发工具 -> 应用系统 数据库系统(DataBase System, DBS) 数据库系统是由数据库、数据库管理系统(及其应用开发工具)、应用程序和数据库管理人员组成的存储、管理、处理和维护数据的系统 数据库管理 数据库管理是指对数据进行分类、组织、编码、存储、检索和维护 数据库管理技术的历史:人工管理 -> 文件系统 -> 数据库系统 人工管理阶段特点: 数据不保存 应用程序管理数据 数据不共享 数据不具有独立性 文件系统阶段特点: 数据可以长期保存 由文件系统管理数据 数据共享性差,冗余度大 数据独立性差 数据库系统的特点: 数据结构化 数据库系统实现整体数据的结构化,这也是其与文件系统的本质区别 结构化是指数据库中的数据不再仅针对某一具体应用,而是面向整个组织或企业 数据的共享性高、冗余度低且易扩充 数据的共享减少数据冗余,节约存储空间,避免数据之间的不相容性和不一致性 由于结构化使得数据库系统弹性大,易于扩充 数据独立性高 物理独立性:应用程序和物理存储是相互独立的 逻辑独立性:应用程序和逻辑结构是相互独立的 数据独立性是由二级映像功能来保证的 数据由数据库管理系统统一管理和控制 数据安全性保护 数据完整性检查 并发控制 数据库恢复 数据模型 数据模型分两类:第一类是概念模型,第二类是逻辑模型和物理模型 概念模型主要用于数据库设计 逻辑模型主要用于数据库管理系统的实现;常用的逻辑模型:层次模型、网状模型、关系模型、面向对象数据模型、 对象关系数据模型、半结构化数据模型等 物理模型描述数据在系统内部的表示方式和存取方法 概念模型的一种表示方法:实体-联系方法(Entity-Relationship),即E-R图 数据模型的组成要素:数据结构、数据操作、数据的完整性约束条件 关系模型术语对比 关系术语 一般表格的术语 关系名 表名 关系模式 表头(表格的描述) 关系 (一张)二维表 元组 记录或行 属性 列 属性名 列名 属性值 列值 分量 一条记录中的一个列值 非规范关系 表中有表(大表中嵌有小表) 关系的完整性约束条件 实体完整性 参照完整性 用户定义的完整性 数据库系统的结构 数据库系统的三级模式结构是指数据库系统是由外模式、模式和内模式三级构成,分别代表数据的三个抽象级别 模式:也称为逻辑模式,是数据库中全体数据的逻辑结构和特征的描述,是所有用户的公共数据视图 MySQL中的database等价于这里的模式 一个数据库只有一个模式 外模式:也称为子模式或用户模式,它是数据库用户能够看见和使用的局部数据的逻辑结构和特征的描述,是数据库用户的数据视图,是与某一应用有关的数据的逻辑表示 外模式通常是模式的子集 MySQL中的视图和SELECT出的结果(部分基本表)等价于这里的外模式 外模式可用来保证数据库安全性,用户只能访问和看见所对应的外模式中的数据 内模式:也称为存储模式,它是数据物理结构和存储方式的描述,是数据在数据库内部的组织方式 一个数据库只有一个内模式 数据库的二级映射功能与数据独立性 外模式/模式映像 当模式改变时,由数据库管理员对各个外模式/模式的映像作相应改变,可以使外模式保持不变;应用程序是依据数据的外模式编写的,从而应用程序不必修改,保证了数据与程序的逻辑独立性,简称数据的逻辑独立性 模式/内模式映像 当数据库的存储结构改变时,由数据库管理员对各个模式/内模式的映像作相应改变,可以使模式保持不变,从而应用程序也不必改变,保证了数据与程序的物理独立性,简称数据的物理独立性 数据库的二级映射保证了数据库外模式的稳定性,从而从底层保证了应用程序的稳定性(一般不需要修改) 数据与程序之间的独立性使得数据的定义和描述可以从应用程序中分离出去 数据库系统的组成 数据库系统是由数据库、数据库管理系统(及其应用开发工具)、应用程序和数据库管理人员组成 硬件平台及数据库 软件 人员","categories":[{"name":"数据库原理","slug":"数据库原理","permalink":"https://godway999.github.io/categories/数据库原理/"}],"tags":[]}]}