Total Pageviews

2018/09/09

[Neo4j] Importing using Load CSV

假設我想要在 neo4j 建立起下圖的關係

由關係圖可以看出會有七個節點,包含
  • 哆啦A夢
  • 大雄
  • 靜香
  • 小夫
  • 胖虎
  • 小叮鈴
  • 玉子 (大雄的媽媽)
  • 伸助 (大雄的爸爸)

這七個人 (nodes) 之間的有九個關係:

  • 大雄的寵物是哆啦A夢
  • 大雄的配偶是靜香
  • 大雄的朋友是小夫
  • 大雄的朋友是胖虎
  • 小夫的朋友是胖虎
  • 哆啦A夢的妹妹是小叮鈴
  • 大雄的爸爸是伸助
  • 大雄的媽媽是玉子
  • 伸助的配偶是玉子

分析與執行步驟如下:


步驟如下:
(1) Prepare CSV file for nodes with UTF-8 encoding and store in neo4j-community-3.3.3\import

(2) Prepare CSV file for relationships with UTF-8 encoding and store in neo4j-community-3.3.3\import

(3) Prepare"load csv" command to load nodes and execute from neo4j browser
using periodic commit 
load csv with headers from
"file:///nodes.csv"
as nodes
create(:Person {id:nodes.node, name:nodes.name, gender:nodes.gender})

產生節點如下:


(4) Prepare"load csv" command to create relationships and execute from neo4j browser
using periodic commit 
load csv with headers from
"file:///relationships.csv"
as line
match (from:Person), (to:Person) where from.id=line.From and to.id=line.To 
create (from)-[:REL {type: line.`Relation Type`}]->(to)

建立關係後如下:


由於,我們期待的圖形是下圖,故會執行步驟 5, 6 來做關係的 rename

(5) Execute additional "cleanup" step for Labels and RelTypes
根據步驟 4 所建立的關係,依據關係的屬性,加以rename,重複建立一條有關係
//Create duplicate relationship with appropriate type
MATCH (n1)-[r1:REL{type:'SPOUSE_OF'}]->(m1),
      (n2)-[r2:REL{type:'PET_OF'}]->(m2),
      (n3)-[r3:REL{type:'FRIEND_OF'}]->(m3),
      (n4)-[r4:REL{type:'SISTER_OF'}]->(m4),
      (n5)-[r5:REL{type:'MOTHER_OF'}]->(m5),
      (n6)-[r6:REL{type:'FATHER_OF'}]->(m6)
merge (n1)-[:SPOUSE_OF]->(m1)
merge (n2)-[:PET_OF]->(m2)
merge (n3)-[:FRIEND_OF]->(m3)
merge (n4)-[:SISTER_OF]->(m4)
merge (n5)-[:MOTHER_OF]->(m5)
merge (n6)-[:FATHER_OF]->(m6)

建立新的關係後,圖形如下:

(6) Remove duplicate relationships
此步驟將會清理多餘的關係,將原本所建立的 REL 關係予以刪除
//Remove duplicate relationships
match ()-[r:REL]-() delete r;

刪除後,圖形如下:


2018/09/08

[PostgreSQL] org.postgresql.util.PSQLException: ERROR: operator does not exist: text = bytea

Problem
When I try to execute the following select SQL statement:
1
2
3
4
5
  select case when (domain_projects <> :domain_projects) then true else false end as result
  from project
  where domain_classifier = true
  and id = :projectId
  and domain_projects is not null

I get this error message:
  org.postgresql.util.PSQLException: ERROR: operator does not exist: text = bytea
  Hint: No operator matches the given name and argument type(s). 
  You might need to add explicit type casts.


How-To
The problem result from the first line:
1
2
3
4
5
  select case when (domain_projects <> :domain_projects) then true else false end as result
  from project
  where domain_classifier = true
  and id = :projectId
  and domain_projects is not null


I need to cast the parameter to specific data type as per instructions. Therefore, the SQL statement should be modified as bellows:
1
2
3
4
5
6
  select
  case when (domain_projects <> cast(:domain_projects as text)) then true else false end as result
  from project
  where domain_classifier = true
  and id = :projectId
  and domain_projects is not null  


2018/09/07

[Spring MVC] Upload ZIP file to server

Scenario

The file structure in ZIP file looks like:


How-To
Here has sample code:
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
    @Transactional
    @PostMapping(value = "/{projectId}/importFile/{fileType}", produces = MediaType.APPLICATION_JSON_VALUE)
    public void importFile(@PathVariable Integer projectId, @PathVariable String fileType,
            @RequestParam(value = "file", required = true) MultipartFile file) throws IOException {

        Project project = repo.findOne(projectId);

        File tmpFile = null;
        DateFormat dateFormat = new SimpleDateFormat("yyyyMMddHHmmss");
        String currentTime = dateFormat.format(new Date());
        try {
            tmpFile = File.createTempFile(file.getName() + "_" + currentTime, ".zip");
            tmpFile.deleteOnExit();
        } catch (IOException e) {
            throw new RuntimeException("建立 temp file 發生錯誤, 錯誤原因: " + e.getMessage(), e);
        }

        InputStream inputStream = null;
        ZipFile zipFile = null;
        try {
            inputStream = file.getInputStream();
            byte[] buffer = new byte[inputStream.available()];
            inputStream.read(buffer);

            Files.write(buffer, tmpFile);

            zipFile = new ZipFile(tmpFile);

            Enumeration<? extends ZipEntry> entries = zipFile.entries();
            while (entries.hasMoreElements()) {
                ZipEntry entry = entries.nextElement();

                saveDomainJSON(project, entry, zipFile);
                saveStoryMD(project, entry, zipFile);
            }

            repo.updatePersistModelToNull(projectId);
        } catch (IOException e) {
            throw new RuntimeException("讀取 zip file 發生錯誤, 錯誤原因: " + e.getMessage(), e);
        } finally {
            if (zipFile != null) {
                zipFile.close();
            }
            if (inputStream != null) {
                inputStream.close();
            }
        }
    }    
 
    private void saveDomainJSON(Project project, ZipEntry entry, ZipFile zipFile) throws IOException {
        if (entry.getName().startsWith("domain")) {
            try (InputStream inputSteam = zipFile.getInputStream(entry);) {
                String content = IOUtils.toString(inputSteam, org.apache.commons.io.Charsets.UTF_8);
                // save content into database
            } catch (IOException e) {
                throw new RuntimeException("讀取 domain JSON file 發生錯誤, 錯誤原因: " + e.getMessage(), e);
            }
        }  
    }
 
    private void saveStoryMD(Project project, ZipEntry entry, ZipFile zipFile) throws IOException {
        if (entry.getName().startsWith("story")) {
            try (InputStream inputSteam = zipFile.getInputStream(entry);) {
                String content = IOUtils.toString(inputSteam);
                // save content into database
            } catch (IOException e) {
                throw new RuntimeException("讀取 story Markdown file 發生錯誤, 錯誤原因: " + e.getMessage(), e);
            }
        }  
    }




2018/09/06

[Spring MVC] Download ZIP file from server

Scenario


How-To
Sample code:
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
    @PostMapping(value = "/{projectId}/downloadZIP", produces = "application/zip")
    public FileSystemResource downloadZIP(@PathVariable Integer projectId, Alerter alerter) throws Exception {
        String identifier = repo.getOne(projectId).getIdentifier();

        DateFormat dateFormat = new SimpleDateFormat("yyyyMMddHHmmss");
        String currentTime = dateFormat.format(new Date());

        String fileName = identifier + "-" + currentTime;
        String domainJSON = projectService.getDomainJSON(projectId);
        String storyMD = projectService.getStoryMD(projectId);

        File tempFile = File.createTempFile(fileName, ".zip");
        tempFile.deleteOnExit();

        try (OutputStream fos = new FileOutputStream(tempFile);
             BufferedOutputStream bos = new BufferedOutputStream(fos);
             ZipOutputStream zos = new ZipOutputStream(bos);) {
            
            zos.putNextEntry(new ZipEntry("domain-" + currentTime + ".json"));
            zos.write(domainJSON.getBytes());
            zos.closeEntry();

            zos.putNextEntry(new ZipEntry("story-" + currentTime + ".md"));
            zos.write(storyMD.getBytes());
            zos.closeEntry();

        } catch (IOException e) {
            throw new RuntimeException("檔案匯出失敗, 錯誤原因:" + e.getMessage(), e);
        }

        return new FileSystemResource(tempFile);
    }


2018/09/05

[閱讀筆記] Antifragile: Things That Gain from Disorder (4/10)


  1. 越不預測未來,就越能適應錯誤與意外,反脆弱性就越強。每一次的錯誤或災難都等於是找出資訊的有價值/有意義嘗試,不斷地獲得教訓與改進的方向
  2. 在演化的過程中,為了讓有機體 (或基因) 越來越好,會需要讓某些較脆弱的有機體被取代或死去,避免較脆弱的有機體繁衍下一代。較高層級的反脆弱,需要犧牲較低層級的脆弱
  3. 人們很難理解要建立一個讓所有人都不會落下的系統,反而會將大家都往下拉,持續發生錯誤並加以改進,才能讓系統永續保存。很弔詭的是,許多政府想要透過社會政策來進行干預,結果反而傷害到最脆弱與最底層的那群人
  4. 如果你是一隻貓,那你最好先搬離有許多狗居住的地方,而不是先磨利自己的爪子;如果你已經看出你所處的職業、行業是脆弱的,那你要做的應該是先轉行,而不是繼續鍛煉自己在那一方面的能力
  5. 槓鈴策略 (barbell strategy) 是一種同時採取兩種極端的策略,一端非常保守,一端非常激進,沒有中間的溫和地帶。反脆弱性是積極主動加上保守偏執的組合——消除不利因素,保護自己免受極端傷害,同時讓有利因素或正面的「黑天鵝」順其自然地發揮效用
  6. 不讓自己去面對適當的「壞事」,就不會有真正的成長,過度干預而獲得的穩定都只是在打造脆弱,最後,負面的黑天鵝會出現,只是沒有人能夠準確的預測到底是幾時而已。那麼,我們該怎麼應對不知幾時會出現的負面黑天鵝呢?甚至反過來想,我們是否能從黑天鵝事件中獲益呢?
  7. 物種間 (species) 有潛在的反脆弱,不同的物種有不同的 DNA 資訊,有些物種會比較脆弱,為了整體物種的群體利益,較脆弱的物種就會被犧牲或淘汰
  8. 「因為每個人都這麼做」並不會使事情變成正確,但大家卻經常誤解。社會執行似乎沒有道理的活動行之有年,而且因為未知的理由而繼續堅持做下去。
  9. 在雅典國家奠基者提修斯(Theseus)的傳說中,從墨加拉到雅典途中有個非常殘暴的強盜,叫 Procrustes 意思是“拉長者”、“暴虐者”。 Procrustes 開設黑店,攔截過路行人。他刻意設置了 2 張鐵床,一個長,一個短。然後他強迫旅人躺在鐵床上,身材矮者睡長床,強拉其軀體使其與床鋪等齊;身材高大的睡短床,他就用利斧把旅客伸出來的腿腳截短。由於他這種特殊的殘暴方式,人稱之為“鐵床匪”。Procrustean Bed 它的涵意是:強求一致的;削足適履、牽強附會的;迫使就範的。
  10. 人們想用 linear 的方式解決 nonlinear 世界的問題,就是一種最常見的 Procrustean Bed
  11. 持續小的變化與壓力,可以讓人去適應、調整環境的變化。壓力因子 (stressor)給予你寶貴的資訊,在職場面臨持續的壓力因子,會逼迫你去適應不同的環境,較不容易被突如其來的黑天鵝擊潰
  12. 人為的穩定是脆弱的來源,隨著變動而做出調整,才能趨向健全與反脆弱
  13. 極端世界中的任何非生物系統,如果沒有變動,都是在累積無聲的風險。
  14. 人生中的一大錯覺是,認為隨機的風險高,所以是壞事,以為消除隨機,就能消除風險,平常世界 (mediocristan) 有許多變異,可是不會發生單一極端的變異;極端世界 (extremistan) 很少出現變異,但是一有變異,就非常極端
  15. 人類常用線性分析進行未來推論,如同自以為能安然度過11月的倒楣火雞 (因為不知道月底感恩節的到來),當感恩節那天突然被抓去宰了,這樣的突發、令人吃驚的事件,就是黑天鵝事件 (black swan event)
  16. 單靠過去資料所得到的結論, 如同讓火雞安全感最大 的那一天,也成為牠危機最大的那一天,因為牠成了感恩節桌上的大餐。對火雞來說,這是一次「黑天鵝事件」,但對屠夫來說,不是,這一切並非意外。
  17. 具有反脆弱性的事物,在適當的壓力因子驅使下,例如截止日期、競爭、老闆的臉色、客戶的反應...等等,我們可以把事情做得更好。想想一旦沒有任何壓力或刺激性,鐵定是一份無趣,且相當容易被取代 (脆弱) 的工作。
  18. 「沒有傷害證明」不等於「證明沒有傷害」,這樣的錯誤經常盛行於知識界,也深植社會學。所以我們的人生使命很簡單,就是如何不當火雞,或者如何避免火雞擁有的特性,也就是具反脆弱性。
  19. 定期出現的小型森林野火,可以將最容易引燃的物質定期燒掉、清理掉。若一昧地有系統性地預防森林大火發生的話,只要發生一次就會造成嚴重的後果
  20. 市場缺乏震盪的話,會導致隱藏的風險不斷累積。當沒有遭受市場衝擊的時間越長,當騷動發生時造成的損害與衝擊就會越大
  21. 反脆弱性是所有倖存下來的自然和複雜系統的特徵,一切自下而上的事物在適量的壓力和混亂下反而能夠蓬勃發展,如果剝離波動性、隨機性和壓力源,反倒會發生傷害。經濟調控者一直通過壓制隨機性和波動性來迫使經濟遵循周期規律,與之類似的還有健康、教育等其他方面的管理,「正如極為焦慮、過度保護子女的父母。那些試圖幫助我們的人往往會對我們造成最大的傷害」。
  22. 在政治或是經濟體系中,若缺乏風暴的影響時間越長,就越容易產生黑天鵝事件,產生的負面影響就會越大
  23. 沒有波動就沒有穩定 (no stability without volatility)。所謂的均衡與穩定,其實是建構在不斷的變動與動盪上
  24. 長期的穩定有如貸款,終究必須償還,若時間拉得越長,連本帶利就要還更多
  25. 委託-代理問題(principal–agent problem),又稱代理問題(Agency problem),代理兩難(agency dilemma),指委託人(principal)與代理人(agent)之間因目標不一致,而產生利益衝突之情事。當代理人本身存在某種動機,驅使他的行為目標著重在於增加自身的利益,而不是增加委託人的利益,就會出現這個兩難現象。研究這個問題在政治科學與經濟學中獲得很大的重視。此類的衝突問題,常見於股票經紀人或是醫生,他們所關心的可能是自己的薪水帳戶,而不是你財務或健康狀況
  26. 天真的干預例子之一是醫療傷害 (iatrogenics),即治療受到的傷害超過利益。作者提出醫療傷害的兩項原則︰一,我們不需要有證據證明受到傷害,才能宣稱某藥物或不自然的肯定療法有危險,舉證責任在醫療一方;二,醫療傷害影響並非線性,對幾乎健康的人我們不應冒險,對正處於危險者則應冒高很多的風險。社會學理論與政策的醫療傷害在現實世界上非常脆弱,在風險分析上也不穩定,原因是政治與經濟的尾端事件無法預測。但作者說他不是反對干預,我們應該出手限制規模大小、集中程度與速度,以降低黑天鵝風險。
  27. Hackers 可以讓你的系統更加強壯;對書籍嚴厲的批評,反而會幫助書籍快速散播、提升銷售量
  28. 在經濟領域,應該盡早淘汰脆弱的企業,讓他們儘早失敗、重新來過,避免拖得太久,對整個系統產生長期的損害或災難
  29. 是否干預需要有一套準則,拖延、觀察事件演變、見機而作,反而有助於避免過度干預、做一些沒必要的事
  30. 人性的拖延,反而是一種內建的保護機制,能做大事的大人物通常不會過度反應、隨著當前的資訊起舞,只在必要時有所反應,一旦他動怒大家都知道事情嚴重,非嚴肅面對不可。


2018/09/04

[閱讀筆記] How Will You Measure Your Life? (1/4)


  1. 人生三大問題:
    1. 如何確保職業生涯成功與快樂?
    2. 如何使自己與配偶、子女與摯友的關係成為一個永恆的快樂源泉?
    3. 如何確保正直的人生?(免除牢獄之災)
  2. 很多人常認為最好的預測未來的方法,是做決策前盡可能地蒐集夠多的資料。但是,這就像開車只看照後鏡,不看前方,你搜集到的資料,代表的是過去已發生的事實,無法用來預測未來
  3. 好的理論可以協助我們分類、解釋,最重要的是,還可以協助我們做預測
  4. 經驗可以是好的老師,但是我們無法承受要經過好幾次嘗試才學會。例如你不希望透過結多次婚姻來學會如何當個好伴侶;你也不希望等到你最後一個孩子出生才學會如何為人父母。這就是為什麼理論這麼寶貴,他可以在事情發生前、甚至在你親身經歷前,先解釋給你聽,少走冤枉路
  5. Steve Jobs 曾說:你要如何從工作中得到滿足?唯一方法是,你相信你現在做的是很棒的工作,然而,只有你愛你所做的時候,你才會覺得這是個很棒的工作。如果你還沒找到,請繼續尋找,直到找到為止。
  6. 所謂的策略,是指你想要達成什麼目標與如何達成預定的目標。在企業界,策略包含企業的執行優先順序、如何回應機會與威脅、如何分配企業寶貴的資源等;對於每個人在職場也是如此,你需要每天安排代辦事項的執行優先順序,處理未預期的機會與威脅,妥善分配你的時間、才能與精力等
  7. 如果以時間與考量面向論,策略通常指的是長時間,大範圍(整個公司或是整個技術領域)之規劃。而相對而言之短時間,特定問題解決之規劃即稱為戰術(tactics),例如常聽得的迂迴戰(強調”技”),即是戰術之一。以動腦與動手比擬,策略重動腦,亦即重規劃能力,而後續之動手(hands on),通常指對應之執行力。總的來說,目標設定->策略->執行等三步驟可以當成問題解決之完成程序,如果再以 PDCA (Plan-Do-Check-Act) 環論,P步驟包括目標設定與擬定策略執行方針,D即執行,其餘兩步驟(即C與A)即是執行後的改善與計劃的完善使得計劃的可執行性提高與持續執行。
  8. 當我們計畫要怎麼做了以後,總是會遇到未預期的機會與威脅,記住,永遠有比我們原先計畫更好的方案。當遇到阻礙難行時,就要去想出較好的方案,並管理手上資源來推動
  9. 當你在做決策時,起點一定是做好優先順序排序,優先做最重要的事情。例如,你認為你職涯最重要的事情是什麼?這個問題會與你是否在職涯生活感到快樂息息相關
  10. 只有策略是不夠的,你還要配置資源、付諸實行。如果你沒有有花時間、精力與才能在你制定的策略,一切都是空談
  11. 在你的職場生活中,一定會有持續不斷的需求在消耗你的時間與注意力。你該如何做好決策,分配資源到對的需求上,是非常重要的事情。人們在分配資源時常會陷入一些陷阱,如將時間分配到叫最大聲的需求、將他們的才能分配到可以快最獲得報酬的需求。這些都是很危險的方式,也是很壞的決策
  12. 如何才能找到真正喜愛的「工作」? 則需評估在工作生涯中,你覺得最重要的是什麼? 但最重要的不一定是會讓你快樂的因素。
  13. 誘因理論 (incentive theory) 認為只要提供足夠的誘因(money),人就會有好表現,樂於工作。但誘因理論不能解釋為何有些人在沒有獲取金錢報酬的情形下也可樂於工作,例如在非營利組織、慈善機構工作者、義工等等,而且你很少會聽到非營利組織的主管在抱怨不知如何激勵底下的成員,即便這些成員如果在私人企業可以獲得更好的薪資水準,但這群人卻擁有很高的工作滿足感,且鮮少抱怨。
  14. 真正的激勵 (motivation) 是讓人們因為內心想去做,而非只是為了金錢。這種形態的激勵,才能讓人在順境或逆境時,持續不斷地做下去
  15. Herzberg 提出動機理論 (motivation theory) ,又稱為雙因素理論 (two-factor theory):「保健因素」(hygiene factors, 包括地位、薪水、工作環境、上司、同事、公司政策等)以及「動機因素」(motivators, 包含挑戰性、得到認可、責任、覺得有意義、個人成長等發自內心)。請注意,薪水是被歸類為保健因素而非動機因素。若一份工作能滿足保健因素,充其量也只能讓你不討厭這份工作,但無法讓你熱愛它
  16. 工作不滿意的相反並不是工作滿意,而是讓工作不滿意消失。hygiene factors (保健因素) 包含安全與舒適的工作環境、與同事以及主管擁有良好的關係、擁有足夠的薪水來照顧自己與你的家人等。若沒有這些東西,你就會在工作感覺不滿意,但是擁有這些東西並不會讓你愛上這份工作,只會讓你不憎恨這份工作
  17. 金錢只能緩和挫折感,要發現真正的快樂,必須要不斷的尋找有意義的機會,可以學到新東西。hygiene factors (保健因素) 是樂在工作的副產品
  18. 若你在工作獲得激勵因素 (motivators),即便你沒有賺很多錢 (但擁有足夠的薪水來照顧你的家人),你還是會愛你所擇
  19. 如果你想幫助他人,就去當主管。底下的員工每天花八小時幫你工作,你有機會去幫每個人規劃適合、有意義、有成長機會的工作內容,讓每個人的生活充滿激勵因素 (motivators)
  20. 追逐金錢只能減輕你在職場上的挫折感。若要追求快樂與幸福,你需要持續去尋找你深信有意義的、可以學習新知的的工作機會,並願意承擔更多責任在肩膀上
  21. 人生苦短,你應該去找你喜愛的工作。真的喜愛他們工作的人,一定覺得自己做的是很有意義的工作的人,每天必然充滿幹勁,進一步發展出與眾不同的競爭優勢
  22. 充滿激勵因素 (motivators)的工作,必然會有好的表現,也會直接反應在薪資,兩者在薪資報酬上會有正相關
  23. 永遠要記得,金錢、地位、獎金與穩定的工作都只是 hygiene factors,這些都是樂於工作的副產品。若你要追尋樂於工作,這些都不是重點
  24. 很多人在職場上不對追求顯性的 (tangible) 事物,如較高的薪水、較高的職稱、較好的獨立辦公室等,這些都是你的親友可以直接看到的表徵,但這些追求都只是在追求海市蜃樓,你追求不到快樂
  25. 若你想快樂工作,問問自己以下問題 (這些都是真的會激勵你的激勵因素):
    1. 目前工作對我有意義嗎?
    2. 目前工作是否讓我有發展的機會?
    3. 是否可以學習到新事物?
    4. 所完成的成就是否有機會獲得認可?
    5. 未來是否會承擔更多責任?