Kết quả của giải thuật phân cụm phân cấp được trình bày theo

Một phần của tài liệu Table union cho dữ liệu dạng json trong open data (Trang 53 - 66)

II. PJK烏O"X影"XÉ"P浦K"FWPI<

4 Hiện thự c Đánh giá

3.3 Kết quả của giải thuật phân cụm phân cấp được trình bày theo

dendrogram

Mục đích, kết quả của bước này là tạo ra các "ánh xạ"(mapping) giữa các tập dữ liệu và các "cụm"(cluster) các tập dữ liệu có thể kết hợp (union) lại với nhau. Mỗi "ánh xạ"sẽ bao gồm một danh sách các ánh xạ - tạm gọi các ánh xạ này là "ánh xạ con"(sub-mapping). Danh sách các ánh xạ này biểu diễn phương pháp các tập dữ liệu với nhau. Mỗi "ánh xạ con"(sub-mapping) sẽ đại diện cho một cặp thuộc tính tương đương nhau giữa hai tập dữ liệu và mỗi "ánh xạ con"chỉ duy nhất biểu diễn quan hệ giữa hai thuộc tính giữa hai tập dữ liệu. Nó khơng biểu diễn quan hệ giữa một thuộc tính trong một tập dữ liệu với nhiều thuộc tính trong một tập dữ liệu khác. Qua đó, tập hợp các "ánh xạ"sẽ biểu diễn cách thức để kết hợp (union) các tập dữ liệu.

Phương pháp để tạo ra "mapping"giữa hai tập dữ liệu:

1. Tính tốn độ giống nhau của từng thuộc tính trong tập dữ liệu thứ nhất với từng thuộc tính trong tập dữ liệu thứ hai để tìm ra các "sub-mapping"và similarity score tương ứng của chúng. Trong luận văn, tôi chỉ sử dụng độ Set Unionability. Tuy nhiên, các độ đo khác có thể được sử dụng ở đây.

2. Tìm ra tồn tộ các "mapping"hợp lệ. Một "apping"gọi là hợp lệ khi khơng có hai "sub-mapping"nào cùng ánh xạ tới cùng một thuộc tính.

3. Tính điểm của từng "mapping". Điểm này được tính bằng cách lấy tích của tồn bộ các "sub-mapping".

4. Tìm "mapping"tốt nhất trong số các "mapping"với tiêu chí: "mapping"tốt nhất là "mapping"có điểm cao nhất và sẽ bao phủ đủ một số lượng thuộc tính đủ nhiều của hai tập dữ liệu. Trong luận văn này, nếu "mapping"bao phủ đủ ít nhất một nửa thuộc tính của một tập dữ liệu thì được xem là họp lệ. Nếu khơng tìm được "mapping"nào thỏa được điều kiện thì "mapping"sẽ là một danh sách rỗng và có similarity score tương ứng là 0.

5. Trả về "mapping"tốt nhất và điểm tương ứng của nó.

Với giải thuật tạo "sub-mapping"như trên, tơi đề xuất phương pháp tìm các "mapping"giữa cá tập dữ liệu trong datastore:

1. Tạo ra ma trận khoảng cách (distance matrix): Với mỗi tập dữ liệu trong datastore, tìm "mapping"tốt nhất của nó với mọi tập dữ liệu cịn lại theo phương pháp đã nêu ở trên.

2. Sử dụng giải thuật phân cụm phân cấp trên ma trận khoảng cách trên để phân cụm dữ liệu.

3. Lưu lại kết quả phân cụm và các thông tin liên quan như "maping", dendogram. Tóm lại, trong bước này, tơi sẽ tạo ra các "mapping"của các tập dữ liệu trong datastore. Kết quả của bước này sẽ là "cụm"các tập dữ liệu có thể được kết hợp (unionize) và phương thức kết hợp các tập dữ liệu đó. Ngồi ra, phương pháp đê tạo ra các "mapping"là hồn tồn độc lập về dữ liệu, khơng phụ thuộc vào các kết quả có trước nên hồn tồn có thể được song song hóa bằng các giải pháp song song hóa sẵn có như Apache Spark [38].

3.2.3 Union Step

Trong bước này, chúng ta tiến hành kết hợp các "cụm"tập dữ liệu thành các tập dữ liệu kết hợp. Ý tưởng chính của bước này là sẽ sử dụng các kết quả của Clustering

Step để tiến hành kết hợp (uninize) các tập dữ liệu lại với nhau. Do sử dụng giải thuật gom cụm phân cấp nên kết quả của Clustering Step sẽ bao gồm các "bước"để gom cụm các tập dữ liệu cho tới tạo thành một tập dữ liệu lớn nhất.

Các bước cụ thể như sau, với mỗi "bước"trong kết quả của giải thuật gom cụm:

1. Kiểm tra xem khoảng cách giữa hai tập dữ liệu có đủ nhỏ (bằng cách so sánh khoảng cách này với một ngưỡng - threshold nào đo. Nếu được thì tới bước tiếp theo, khơng thì tới bước 4.

2. Kết hợp (unionize) hai tập dữ liệu này thành một tập dữ liệu kết hợp theo "mapping’ đã tạo ra ở Clustering Step.

3. Đánh dấu hai dataset này đã được kết hợp, thêm tập dữ liệu kết hợp vào datastore.

4. Lấy "bước"tiếp theo từ kết quả phân cụm và trở về bước 1. Nếu khơng cịn "bước"thì tới bước tiếp theo

5. Lưu các tập dữ liệu ban đầu chưa được kết hợp (chưa được đánh dấu) vào datastore đích.

6. Lưu các tập dữ liệu kết hợp vào datastore đích.

Có thể nhận ra rằng, Union Step là một bước hoàn toàn dựa vào kết quả của Clustering Steps. Ngồi ra, có thể nhận ra rằng, Union Step cũng có khả năng được song song hóa về mặt dữ liệu bằng các cơng cụ như Apache Spark[38].

Hiện thực - Đánh giá

4.1 Môi trường hiện thực và công cụ sử dụng Môi trường tiến hành hiện thực, đánh giá như sau:

• Hệ điều hành: Ubuntu, version 21.04 • Processor: Intel Core i5-10300H

• RAM: 16 GB

• MongoDB:

– Version 4.4

– Triển khai dưới dạng docker-container thơng qua docker-compose. • Docker: version 20.10.8

• Ngơn ngữ lập trình: Python version 3.8.8

4.2 Hiện thực

Trong luận văn này, tôi chỉ tiến hành hiện thực, đánh giá một phần phương pháp. Cụ thể, tôi sẽ không tiến hành hiện thực kết hợp dữ liệu mà chỉ tiến hành hiện

thực, đánh giá đến phần gom cụm các tập dữ liệu. Đây là bởi vì vấn đề gom cụm dữ liệu là vấn đề cốt lõi của bài tốn data union. Nó sẽ quyết định thành cơng hay thất bại của quy trình data union. Bước hiện thực kết hợp dữ liệu sẽ được tiến hành trong các nghiên cứu sau, sau khi đã tích hợp thêm các độ đo độ giống nhau giữa các tập dữ liệu khác.

Quá trình hiện thực bao gồm nhiều module, chức năng khác nhau. Trong đó, đánh chú ý nhất bao gồm:

• Chức năng đo độ giống nhau giữa hai thuộc tính: 1 from helper import nCr , nPr

2 3 def c a l _ u n i o n a b l i l i t y _ e s s e m b i l e ( dataset1 , d a t a s e t 2 ) : 4 return c a l _ s e t _ u n i o n a b i l i t y ( dataset1 , d a t a s e t 2 ) 5 6 def c a l _ s e t _ u n i o n a b i l i t y ( dataset1 , d a t a s e t 2 ) : 7 set1 = set( d a t a s e t 1 ) 8 set2 = set( d a t a s e t 2 ) 9 i n t e r _ s e c = set1 . i n t e r s e c t i o n ( set2 ) 10 11 na = len( set1 ) 12 nb = len( set2 ) 13 14 nd = na + nb 15 t = len( i n t e r _ s e c ) 16 17 result = 0 18 for i in range(0 , t ) : 19 result += c a l _ s u c c e s s f u l _ d r a w _ d i s t r i b u t i o n (i , na , nb , nd ) 20 21 return result 22 23 def c a l _ s u c c e s s f u l _ d r a w _ d i s t r i b u t i o n (s , na , nb , nd ) : 24 result = nCr ( na , s ) * nCr ( nd - na , nb - s ) / nCr ( nd , nb ) 25 return result

Listing 4.1: Chức năng đo độ giống nhau giữa hai thuộc tính

1

2 def g e n _ m a t c h i n g s ( self , data_set1 , d a t a _ s e t 2 ) :

3 atttributes_1 , a t t t r i b u t e _ n a m e _ 1 , c o l _ n a m e _ 1 = d a t a _ s e t 1 4 atttributes_2 , a t t t r i b u t e _ n a m e _ 2 , c o l _ n a m e _ 2 = d a t a _ s e t 2 5 6 m a t c h i n g s = [] 7 8 # Gett a t t r i b u t e m a p p i n g s 9 m a p p i n g s = {} 10 11 max_c = 0 12 13 if len( a t t t r i b u t e s _ 1 ) == 0: 14 return ( None , 0) 15 16 17 for a t t t r i b u t e in a t t t r i b u t e _ n a m e _ 1 : 18 if not a t t t r i b u t e s _ 1 . get ( a t t t r i b u t e ) : 19 print( d a t a _ s e t 1 [2]) 20 print( a t t t r i b u t e s _ 1 . keys () ) 21 print( a t t t r i b u t e _ n a m e _ 1 ) 22 23 result = q u e r r y _ l s h ( a t t t r i b u t e s _ 1 [ a t t t r i b u t e ] , atttributes_2 , c o l _ n a m e _ 2 )

24 if result and len( result ) >0:

25 for item in result :

26 score = c a l _ s e t _ u n i o n a b i l i t y ( a t t t r i b u t e s _ 1 . get ( a t t t r i b u t e ) , a t t t r i b u t e s _ 2 . get ( item ) )

27 m a p p i n g s [( atttribute , item ) ] = score

28 max_c +=1

29

30 b e s t _ c _ m a p p i n g s = []

31

32 for i in range(1 , max_c +1) :

33 score , temp = self . g e t _ b e s t _ c _ m a p p i n g s (i , m a p p i n g s )

34 b e s t _ c _ m a p p i n g s . append (( temp , score ) )

35 # logger . info ( b e s t _ c _ m a p p i n g s )

37 c h o s e n _ m a p p i n g s = ()

38 c h o s e n _ s c o r e = 0

39

40 for mapping , score in b e s t _ c _ m a p p i n g s :

41 c u r r e n t _ i o u = cal_iou ( mapping , a t t t r i b u t e _ n a m e _ 1 , a t t t r i b u t e _ n a m e _ 2 ) 42 43 if score > c h o s e n _ s c o r e and c u r r e n t _ i o u >= I o U _ T h r e s h o l d : 44 c h o s e n _ s c o r e = score 45 c h o s e n _ m a p p i n g s = mapping 46 47 return c ho s en _m a pp in g s , c h o s e n _ s c o r e

Listing 4.2: Chức năng đo độ giống nhau giữa hai thuộc tính

• Chức năng chạy tồn bộ quy trình data union (có kèm theo logging): 1 def run ( self ) :

2 logger . info (’

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ’)

3 logger . info (’ E x t r a c t i n g schema ! ’)

4 self . c o n v e r t S c h e m a ()

5 logger . info ( self . schema )

6 logger . info (’

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ’)

7

8 logger . info (’

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ’)

9 logger . info (’ C r e a t i n g D i s t a n c e Matrix ! ’)

10 logger . info (’ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ’) 11 12 client = g e t D S C l i e n t () [’ t a b l e _ u n i o n _ t e s t ’] 13 c o l l e c t i o n _ n a m e s = client . c o l l e c t i o n _ n a m e s ( i n c l u d e _ s y s t e m _ c o l l e c t i o n s = False ) 14 15 c o l l e c t i o n s = [] 16 17 for c o l _ n a m e in c o l l e c t i o n _ n a m e s :

19 schema = self . schema [1][ c o l _ n a m e ]

20 a t t _ n a m e s = []

21 for key in schema . keys () :

22 if key != ’ pk ’: 23 a t t _ n a m e s . append ( key ) 24 25 a t t t r i b u t e s = {} 26 for record in c o l l e c t i o n : 27 for att in a t t _ n a m e s : 28 name = att

29 temp = a t t t r i b u t e s . get ( name )

30 if temp and record . get ( att ) :

31 temp . append ( record . get ( att ) )

32 a t t t r i b u t e s [ name ] = temp

33 if not temp and record . get ( att ) :

34 a t t t r i b u t e s [ name ] = [ record . get ( att ) ]

35 c o l l e c t i o n s . append (( atttributes , att_names , c o l _ n a m e ) )

36

37 logger . info (’

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ’)

38 logger . info (’ G e n e r a t i n g m a p p i n g s and score ’)

39 logger . info (’

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ’)

40

41 d i s t a n c e _ m a t r i x = [[0 for x in range(len( c o l l e c t i o n s ) ) ] for y in range(len( c o l l e c t i o n s ) ) ]

42 m a p p i n g s = [[() for x in range(len( c o l l e c t i o n s ) ) ] for

y in range(len( c o l l e c t i o n s ) ) ]

43

44 d a t a _ i n p u t = []

45

46 for i in range(len( c o l l e c t i o n s ) ) :

47 for j in range( i +1 ,len( c o l l e c t i o n s ) ) :

48 d a t a _ i n p u t . append (( i ,j , c o l l e c t i o n s ) )

49

50 with futures . P r o c e s s P o o l E x e c u t o r (6) as e x e c u t o r :

51 f u t u r e _ r e s u l t s = []

53 f u t u r e _ r e s u l t s . append ( e x e c u t o r . submit ( self . p a r r a l e l _ p r o c e s s , p a r a m e t e r ) ) 54 55 56 count = 0 57 for result in f u t u r e _ r e s u l t s : 58

59 x , y , mapping , score = result . result ()

60

61 count += 1

62 logger . info (’ F i n i s h e d ’+ str( count ) +’

mapping out of ’ + str(len( f u t u r e _ r e s u l t s ) ) + ’ m a p p i n g s ! ’ ) 63 64 d i s t a n c e _ m a t r i x [ x ][ y ] = (1 - score ) * SCALE 65 d i s t a n c e _ m a t r i x [ y ][ x ] = (1 - score ) * SCALE 66 67 if len( mapping ) : 68 m a p p i n g s [ x ][ y ] = (( c o l l e c t i o n _ n a m e s [ x ] , c o l l e c t i o n _ n a m e s [ y ]) , mapping ) 69 m a p p i n g s [ y ][ x ] = (( c o l l e c t i o n _ n a m e s [ x ] , c o l l e c t i o n _ n a m e s [ y ]) , mapping ) 70 71 72 logger . info (’ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ’) 73 logger . info (’ d i s t a n c e _ m a t r i x ’) 74 logger . info ( d i s t a n c e _ m a t r i x ) 75 76 logger . info (’ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ’) 77 logger . info (’ c o n d e n s e d d i s t a n c e _ m a t r i x ’) 78 tmp = [[0] * len( c o l l e c t i o n s ) ]*len( c o l l e c t i o n s ) 79 80 logger . info (’ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ’)

81 logger . info (’ C l u s t e r i n g data ’)

82 logger . info (’

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ’)

84 logger . info (’ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ’) 85 logger . info ( d i s t a n c e _ m a t r i x ) 86 logger . info (’ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ’) 87 88 c l u s t e r s = hac . linkage ( s q u a r e f o r m ( d i s t a n c e _ m a t r i x ) , ’ average ’) 89 90 logger . info (’ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ’) 91 logger . info ( c l u s t e r s ) 92 logger . info (’ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ’) 93 94 results = {}

95 for i in range(len( c o l l e c t i o n _ n a m e s ) ) :

96 results [ i ] = [ c o l l e c t i o n _ n a m e s [ i ]] 97 count = len( c o l l e c t i o n _ n a m e s ) 98 99 print(’ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ’) 100 print(’ results ’) 101 print( results ) 102 print(’ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ’) 103 104 for step in c l u s t e r s :

105 if float( step [2]) > float( SCALE ) /3:

106 break

107 value1 = results . pop (int( step [0]) )

108 value2 = results . pop (int( step [1]) )

109 results [ count ] = value1 + value2

110 count = count + 1 111 112 print(’ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ’) 113 print(’ results ’) 114 print( results ) 115 print(’ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ’) 116 logger . info (’ c o l l e c t i o n _ n a m e s ’) 117 logger . info ( c o l l e c t i o n _ n a m e s ) 118 logger . info (’ m a p p i n g s ’)

119 logger . info ( m a p p i n g s )

120

121 with open(’ ./ results / ’+ str( d a t e t i m e . d a t e t i m e . now () . t i m e s t a m p () ) + ’. txt ’, ’w ’) as f :

122 for key in results . keys () :

123 f . write (str( key ) +" " + str(

results [ key ]) )

124 f . write (’\ n ’)

Listing 4.3: Chức năng đo độ giống nhau giữa hai thuộc tính

Ngồi ra, dưới đây là cấu hình docker-compose tơi sử dụng: 1 version : ’3 ’ 2 3 volumes : 4 m o n g o d b _ d a t a : 5 6 s e r v i c e s : 7 mongodb : 8 c o n t a i n e r _ n a m e : m o n g o d b _ t a b l e _ u n i o n 9 h o s t n a m e : mongodb 10 image : mongo :4.4 11 e n v i r o n m e n t : 12 - M O N G O _ I N I T D B _ R O O T _ U S E R N A M E = admin 13 - M O N G O _ I N I T D B _ R O O T _ P A S S W O R D = p a s s w o r d 14 volumes : 15 - m o n g o d b _ d a t a :/ data / mongodb 16 ports : 17 - " 2 7 0 1 7 : 2 7 0 1 7 " 18 n e t w o r k s : 19 - m o n g o d b _ w n e t 20 n e t w o r k s : 21 m o n g o d b _ w n e t : 22 driver : bridge

4.3 Đánh giá

Trong luận văn này, tôi sẽ đánh giá về độ khả dụng của phương pháp chứ chưa quan tâm tới độ hiệu quả cũng như hiệu năng của phương pháp. Các nghiên cứu, đánh giá về hiệu năng của phương pháp sẽ được đánh giá trong các nghiên cứu sau, sau khi đã tích hợp thêm các độ đo độ giống nhau khác giữa các tập dữ liệu. 4.3.1 Nguồn dữ liệu

Nguồn dữ liệu được sử dụng đến từ [39] được tạo ra từ dữ liệu đến từ cổng dữ liệu mở của nước Anh và Canada được dùng ở trong [7]. Mỗi datastore thử nghiệm sẽ bao gồm nhiều tập dữ liệu trong [39].

Dữ liệu kiểm thử bao gồm:

• Dữ liệu dạng ngày tháng, bao gồm dữ liệu về thứ trong tuần, tháng của năm và dữ liệu ngày tháng dạng đầy đủ.

• Dữ liệu đường sắt của chính phủ Canada, bao gồm tên cơng ty, các thông tin vận hành đường sắt, các thông tin về địa lý Canada như tỉnh, thành phố, đường phố, thơng tin về các loại đất.

• Thơng tin về các chương trình tài trợ nghiên cứu khoa học, bao gồm lĩnh vực nghiên cứu, hội đồng kiểm duyệt, ứng dụng của nghiên cứu.

4.3.2 Đánh giá

Tôi đã tiến hành một số thí nghiệm trong [40] để đánh giá tính khả dụng của phương pháp dựa trên nguồn dữ liệu đã được nêu ở phần trước. Các thí nghiệm được tiến hành theo phương pháp sau: Sử dụng các tập dữ liệu nhân tạo (synthesized datasets) được tạo ra sẵn ở trong [39]. Các tập dữ liệu nhân tạo này được tạo ra từ một vài tập dữ liệu gốc (orginal datasets). Tôi sẽ áp dụng phương pháp đã được đề cập ở chương trên vào datastore chứa các tập dữ liệu, kết quả thu được sẽ là các tập dữ liệu kết hợp (unionized dataset). Sau đó, tơi sẽ tiến hành so sánh các

Số thứ tự thí

nghiệm Số lập tập dữliệu Số lượng tậpdữ liệu nguyên bản Số lượng tập dữ liệu kết hợp Thí nghiệm số 1 25 2 8 Thí nghiệm số 2 19 4 8 Thí nghiệm số 3 39 4 11 Thí nghiệm số 4 54 4 13 Thí nghiệm số 5 15 1 11 Bảng 4.1: Kết quả thí nghiệm

tập dữ liệu gốc với tập dữ liệu kết hợp về số lượng cũng như thành phần các tập dữ liệu nhân tạo nào tạo thành tập dữ liệu gốc và tập dữ liệu kết hợp.

Trong thí nghiệm 1, 2, 3 and 4 các tập dữ liệu được chọn từ các tập dữ liệu nên có giá trị Set Unionability cao với các tập dữ liệu đến từ cùng một tập dữ liệu gốc. Trong thí nghiệm 5,tơi chọn các tập dữ liệu từ một tập dữ liệu duy nhất. Trong thí nghiệm này, tơi đặc biệt lựa chọn các tập dữ liệu có giá trị Set Unionability thấp với các tập dữ liệu còn lại để kiểm tra xem các tập dữ liệu có giá trị Set Unionability thấp có được gom cụm lại với các tập dữ liệu cịn lại khơng. Các thí nghiệm này dùng để đánh giá khả năng hoạt động của giải thuật trong các trường hợp khác nhau.

Đầu tiên, tôi tiến hành đánh giá phương pháp qua số cụm dữ liệu được tạo ra theo giải thuật và số cụm dữ liệu tối ưu. Số cụm dữ liệu tối ưu được tính bằng số lượng tập dữ liệu gốc (orginal datasets) mà các tập dữ liệu được dùng trong từng thử nghiệm thuộc về.

Kết quả của bước đánh gía đánh giá có thể được xem ở bảng 4.1, dữ liệu đánh

Có thể thấy được, số lượng các cụm dữ liệu được tạo ra vẫn chưa tối ưu: khi giải thuật gom cụm chạy tối ưu, số cụm dữ liệu thực tế sẽ phải bằng tập dữ liệu gốc. Để có thể tìm hiểu rõ hơn lý do cho kết quả này. Tôi tiến hành bước đánh giá tiếp theo. Trong bước đánh giá này, tơi sẽ phân tích, đánh giá xem các tập dữ liệu có được gom cụm chính xác hay khơng: các tập dữ liệu đến từ cùng một tập dữ liệu gốc phải được gom vào một cụm dữ liệu, các tập dữ liệu không cùng một tập dữ liệu gốc phải không được gom vào cùng một cụm dữ liệu.

Trong thí nghiệm 1, các tập dữ liệu có thể được gom thành 2 cụm dữ liệu chính. Tuy nhiên, kết quả giải thuật đã phân dữ liệu thành 8 cụm dữ liệu. Các cụm dữ liệu tối ưu và thực tế như hình sau. Trong đó, viền đen biểu diễn cụm dữ liệu tối ưu, viền xanh biểu dữ diễn cụm dữ liệu thực tế.

Một phần của tài liệu Table union cho dữ liệu dạng json trong open data (Trang 53 - 66)

Tải bản đầy đủ (PDF)

(150 trang)