準(zhǔn)備執(zhí)行Gremlin的圖形化環(huán)境

背景

Gremlin是Apache TinkerPop框架下實(shí)現(xiàn)的圖遍歷語言鹦蠕,支持OLTP與OLAP,是目前圖數(shù)據(jù)庫領(lǐng)域主流的查詢語言在抛,可類比SQL語言之于關(guān)系型數(shù)據(jù)庫钟病。

HugeGraph是國內(nèi)的一款開源圖數(shù)據(jù)庫,完全支持Gremlin語言刚梭。本文將講述如何基于HugeGraph搭建一個(gè)執(zhí)行Gremlin的圖形化環(huán)境肠阱。

HugeGraph的github倉庫下有很多子項(xiàng)目,我們這里只需要使用其中的兩個(gè):hugegraphhugegraph-studio望浩。

部署HugeGraphServer

準(zhǔn)備安裝包

方式一:源碼編譯打包

進(jìn)入hugegraph項(xiàng)目辖所,克隆代碼庫

進(jìn)入終端

$ git clone git@github.com:hugegraph/hugegraph.git

完成后會(huì)在當(dāng)前目錄下多出來一個(gè)hugegraph的子目錄,不過這個(gè)目錄里面的文件是源代碼磨德,我們需要編譯打包才能生成可以運(yùn)行包缘回。

進(jìn)入hugegraph目錄,執(zhí)行命令:

$ git checkout release-0.7
$ mvn package -DskipTests

注意:一定要先切換分支典挑,hugegraph主分支上版本已經(jīng)升級(jí)到0.8.0了酥宴,但是studio似乎還沒有升級(jí),為避免踩坑我們還是使用已發(fā)布版您觉。

經(jīng)過一長串的控制臺(tái)輸出后拙寡,最后如果能看到BUILD SUCCESS表示打包成功。

打包成功日志

這時(shí)會(huì)在當(dāng)前目錄下多出來一個(gè)子目錄hugegraph-0.7.4和一個(gè)壓縮包hugegraph-0.7.4.tar.gz琳水,這就是我們即將要使用可以運(yùn)行的包肆糕。

本人有輕微強(qiáng)迫癥,不喜歡源代碼和二進(jìn)制包放在一起在孝,容易混淆诚啃,所以把hugegraph-0.7.4拷到上一層目錄,然后刪除源代碼目錄私沮,這樣上層目錄又回歸清爽了始赎。

$ mv hugegraph-0.7.4 ../hugegraph-0.7.4
$ cd ..
$ rm -rf hugegraph

到這兒安裝包就準(zhǔn)備好了。不過仔燕,這樣操作是需要你本地裝了jdk造垛、gitmaven命令行工具的,如果你沒有安裝也沒關(guān)系晰搀,我們還可以直接下載hugegraph官方的release包五辽。

方法二:直接下載release

點(diǎn)擊github代碼的上面的導(dǎo)航releases

可以看到hugegraph目前有兩個(gè)release,點(diǎn)擊hugegraph-0.7.4.tar.gz就開始下載了外恕。

releases

下載完之后解壓即可

$ tar -zxvf hugegraph-0.7.4.tar.gz

解壓完之后能看到一個(gè)hugegraph-0.7.4目錄奔脐,這個(gè)目錄和用源碼包打包生成的是一樣的俄周。

下面講解如何配置參數(shù)。

配置參數(shù)

雖然標(biāo)題叫配置參數(shù)髓迎,但其實(shí)hugegraph的默認(rèn)配置就已經(jīng)能在大部分環(huán)境下直接使用了,不過還是說明一下幾個(gè)重要的配置項(xiàng)建丧。

進(jìn)入hugegraph-0.7.4目錄排龄,修改HugeGraphServer提供服務(wù)的url (host + port)

$ vim conf/rest-server.properties
# bind url
restserver.url=http://127.0.0.1:8080

# gremlin url to connect
gremlinserver.url=http://127.0.0.1:8182

# graphs list with pair NAME:CONF_PATH
graphs=[hugegraph:conf/hugegraph.properties]

# authentication
#auth.require_authentication=
#auth.admin_token=
#auth.user_tokens=[]

restserver.url就是HugeGraphServer對(duì)外提供RESTful API服務(wù)的地址,host127.0.0.1時(shí)只能在本機(jī)訪問的橄维,按需要修改其中的hostport部分即可。我這里由于studio也是準(zhǔn)備在本地啟動(dòng),8080端口也沒有其他服務(wù)占用委乌,所以不修改它。

graphs是可供連接的圖名與配置項(xiàng)的鍵值對(duì)列表,hugegraph:conf/hugegraph.properties表示通過HugeGraphServer可以訪問到一個(gè)名為hugegraph的圖實(shí)例耳贬,該圖的配置文件路徑為conf/hugegraph.properties。我們可以不用去管圖的配置文件,按需要修改圖的名字即可挤渔。我這里仍然沒有修改它。

初始化后端

hugegraph啟動(dòng)服務(wù)之前是需要手動(dòng)初始化后端的绕辖,不過大家也不要看到“手動(dòng)”兩個(gè)字就害怕,其實(shí)就是調(diào)一個(gè)命令的事。

$ bin/init-store.sh
Initing HugeGraph Store...
2018-09-07 16:02:12 1082  [main] [INFO ] com.baidu.hugegraph.cmd.InitStore [] - Init graph with config file: conf/hugegraph.properties
2018-09-07 16:02:12 1201  [main] [INFO ] com.baidu.hugegraph.HugeGraph [] - Opening backend store 'rocksdb' for graph 'hugegraph'
2018-09-07 16:02:12 1258  [main] [INFO ] com.baidu.hugegraph.backend.store.rocksdb.RocksDBStore [] - Opening RocksDB with data path: rocksdb-data/schema
2018-09-07 16:02:12 1417  [main] [INFO ] com.baidu.hugegraph.backend.store.rocksdb.RocksDBStore [] - Failed to open RocksDB 'rocksdb-data/schema' with database 'hugegraph', try to init CF later
2018-09-07 16:02:12 1445  [main] [INFO ] com.baidu.hugegraph.backend.store.rocksdb.RocksDBStore [] - Opening RocksDB with data path: rocksdb-data/system
2018-09-07 16:02:12 1450  [main] [INFO ] com.baidu.hugegraph.backend.store.rocksdb.RocksDBStore [] - Failed to open RocksDB 'rocksdb-data/system' with database 'hugegraph', try to init CF later
2018-09-07 16:02:12 1456  [main] [INFO ] com.baidu.hugegraph.backend.store.rocksdb.RocksDBStore [] - Opening RocksDB with data path: rocksdb-data/graph
2018-09-07 16:02:12 1461  [main] [INFO ] com.baidu.hugegraph.backend.store.rocksdb.RocksDBStore [] - Failed to open RocksDB 'rocksdb-data/graph' with database 'hugegraph', try to init CF later
2018-09-07 16:02:12 1491  [main] [INFO ] com.baidu.hugegraph.backend.store.rocksdb.RocksDBStore [] - Store initialized: schema
2018-09-07 16:02:12 1511  [main] [INFO ] com.baidu.hugegraph.backend.store.rocksdb.RocksDBStore [] - Store initialized: system
2018-09-07 16:02:12 1543  [main] [INFO ] com.baidu.hugegraph.backend.store.rocksdb.RocksDBStore [] - Store initialized: graph
2018-09-07 16:02:13 1804  [pool-3-thread-1] [INFO ] com.baidu.hugegraph.backend.Transaction [] - Clear cache on event 'store.init'

這里可以看到赎婚,hugegraph初始化了rocksdb后端饺窿,那為什么是rocksdb而不是別的呢肚医,其實(shí)就是上一步說的conf/hugegraph.properties中配置的舰涌。

$ vim conf/hugegraph.properties
# gremlin entrence to create graph
gremlin.graph=com.baidu.hugegraph.HugeFactory

# cache config
#schema.cache_capacity=1048576
#graph.cache_capacity=10485760
#graph.cache_expire=600

# schema illegal name template
#schema.illegal_name_regex=\s+|~.*

#vertex.default_label=vertex

backend=rocksdb
serializer=binary

store=hugegraph

# rocksdb backend config
#rocksdb.data_path=/path/to/disk
#rocksdb.wal_path=/path/to/disk
...

其中backend=rocksdb就是設(shè)置后端為rocksdb的配置項(xiàng)。

其他的后端還包括:memory搁痛、cassandrascylladb谁尸、hbasemysqlpalo。我們這里不用去管它破婆,用默認(rèn)的rocksdb即可祷舀。

初始化完成之后,會(huì)在當(dāng)前目錄下出現(xiàn)一個(gè)rocksdb-data的目錄亿鲜,這就是存放后端數(shù)據(jù)的地方,沒事千萬不要隨意刪它或移動(dòng)它。

注意:初始化后端這個(gè)操作只需要在第一次啟動(dòng)服務(wù)前執(zhí)行一次,不要每次起服務(wù)都執(zhí)行撬码。不過即使執(zhí)行了也沒關(guān)系夫否,hugegraph檢測到已經(jīng)初始化過了會(huì)跳過。

啟動(dòng)服務(wù)

終于到了啟動(dòng)服務(wù)了叫胁,同樣也是一條命令

$ bin/start-hugegraph.sh
Starting HugeGraphServer...
Connecting to HugeGraphServer (http://127.0.0.1:8080/graphs)....OK

看到上面的OK就表示啟動(dòng)成功了凰慈,我們可以jps看一下進(jìn)程。

$ jps
...
4101 HugeGraphServer
4233 Jps
...

如果還不放心驼鹅,我們可以發(fā)個(gè)HTTP請求試試看微谓。

$ curl http://127.0.0.1:8080/graphs
{"graphs":["hugegraph"]}

到這里HugeGraphServer的部署就完成了,接下來我們來部署HugeGraphStudio输钩。

部署HugeGraphStudio

步驟與部署HugeGraphServer大體類似豺型,我們就不那么啰嗦了。

記得先返回最上層目錄买乃,避免目錄嵌套在一起了姻氨。

準(zhǔn)備安裝包

克隆代碼庫

$ git clone git@github.com:hugegraph/hugegraph-studio.git
Cloning into 'hugegraph-studio'...
mux_client_request_session: read from master failed: Broken pipe
remote: Counting objects: 326, done.
remote: Compressing objects: 100% (189/189), done.
remote: Total 326 (delta 115), reused 324 (delta 113), pack-reused 0
Receiving objects: 100% (326/326), 1.60 MiB | 350.00 KiB/s, done.
Resolving deltas: 100% (115/115), done.

編譯打包

studio是一個(gè)包含前端的項(xiàng)目,使用react.js實(shí)現(xiàn)剪验,自行打包的話需要安裝npm肴焊、webpack等工具。

$ cd hugegraph-studio
$ mvn package -DskipTests

studio打包的時(shí)間會(huì)稍長一點(diǎn)功戚。

...
[INFO] Reactor Summary:
[INFO]
[INFO] hugegraph-studio ................................... SUCCESS [  0.003 s]
[INFO] studio-api ......................................... SUCCESS [  4.683 s]
[INFO] studio-dist ........................................ SUCCESS [01:42 min]
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 01:47 min
[INFO] Finished at: 2018-09-07T16:32:44+08:00
[INFO] Final Memory: 34M/390M
[INFO] ------------------------------------------------------------------------

將打包好的目錄拷到上一層娶眷,刪除源碼目錄(純個(gè)人喜好)。

$ mv hugegraph-studio-0.7.0 ../
$ cd ..
$ rm -rf hugegraph-studio

至此啸臀,我的最上層目錄就只剩下兩個(gè)安裝包届宠,如下:

$ ls
hugegraph-0.7.4        hugegraph-studio-0.7.0

配置參數(shù)

進(jìn)入hugegraph-studio-0.7.0目錄,修改唯一的一個(gè)配置文件壳咕。

$ cd  hugegraph-studio-0.7.0
$ vim conf/hugegraph-studio.properties
studio.server.port=8088
studio.server.host=localhost

graph.server.host=localhost
graph.server.port=8080
graph.name=hugegraph

# the directory name released by react
studio.server.ui=ui
# the file location of studio-api.war
studio.server.api.war=war/studio-api.war
# default folder in your home directory, set to a non-empty value to override
data.base_directory=~/.hugegraph-studio

show.limit.data=250
show.limit.edge.total=1000
show.limit.edge.increment=20

# separator ','
gremlin.limit_suffix=[.V(),.E(),.hasLabel(STR),.hasLabel(NUM),.path()]

需要修改的參數(shù)是graph.server.host=localhost席揽、graph.server.port=8080graph.name=hugegraph谓厘。它們與HugeGraphServer的配置文件conf/rest-server.properties中的配置項(xiàng)對(duì)應(yīng)幌羞,其中:

  • graph.server.host=localhostrestserver.url=http://127.0.0.1:8080host對(duì)應(yīng);
  • graph.server.port=8080與的restserver.url=http://127.0.0.1:8080port對(duì)應(yīng)竟稳;
  • graph.name=hugegraphgraphs=[hugegraph:conf/hugegraph.properties]的圖名對(duì)應(yīng)属桦。

因?yàn)槲抑安]有修改HugeGraphServer的配置文件conf/rest-server.properties,所以這里也不需要修改HugeGraphStudio的配置文件conf/hugegraph-studio.properties他爸。

啟動(dòng)服務(wù)

$ bin/hugegraph-studio.sh

studio的啟動(dòng)默認(rèn)是不會(huì)放到后臺(tái)的聂宾,所以我們會(huì)在控制臺(tái)上看到一大串日志,在最底下看到如下日志表示啟動(dòng)成功:

信息: Starting ProtocolHandler [http-nio-127.0.0.1-8088]
16:56:24.507 [main] INFO  com.baidu.hugegraph.studio.HugeGraphStudio ID:  TS: - HugeGraphStudio is now running on: http://localhost:8088

然后我們按照提示诊笤,在瀏覽器中輸入http://localhost:8088系谐,就進(jìn)入了studio的界面:

studio界面

圖中Gremlin下的框,就是我們輸入gremlin語句進(jìn)而操作hugegraph的入口了,下面我們給出一個(gè)例子纪他。

創(chuàng)建關(guān)系圖

以下內(nèi)容參考CSDN博客通過Gremlin語言構(gòu)建關(guān)系圖并進(jìn)行圖分析鄙煤。

在輸入框中輸入以下代碼以創(chuàng)建一個(gè)“TinkerPop關(guān)系圖”:

// PropertyKey
graph.schema().propertyKey("name").asText().ifNotExist().create()
graph.schema().propertyKey("age").asInt().ifNotExist().create()
graph.schema().propertyKey("addr").asText().ifNotExist().create()
graph.schema().propertyKey("lang").asText().ifNotExist().create()
graph.schema().propertyKey("tag").asText().ifNotExist().create()
graph.schema().propertyKey("weight").asFloat().ifNotExist().create()

// VertexLabel
graph.schema().vertexLabel("person").properties("name", "age", "addr", "weight").useCustomizeStringId().ifNotExist().create()
graph.schema().vertexLabel("software").properties("name", "lang", "tag", "weight").primaryKeys("name").ifNotExist().create()
graph.schema().vertexLabel("language").properties("name", "lang", "weight").primaryKeys("name").ifNotExist().create()

// EdgeLabel
graph.schema().edgeLabel("knows").sourceLabel("person").targetLabel("person").properties("weight").ifNotExist().create()
graph.schema().edgeLabel("created").sourceLabel("person").targetLabel("software").properties("weight").ifNotExist().create()
graph.schema().edgeLabel("contains").sourceLabel("software").targetLabel("software").properties("weight").ifNotExist().create()
graph.schema().edgeLabel("define").sourceLabel("software").targetLabel("language").properties("weight").ifNotExist().create()
graph.schema().edgeLabel("implements").sourceLabel("software").targetLabel("software").properties("weight").ifNotExist().create()
graph.schema().edgeLabel("supports").sourceLabel("software").targetLabel("language").properties("weight").ifNotExist().create()

// TinkerPop
okram = graph.addVertex(T.label, "person", T.id, "okram", "name", "Marko A. Rodriguez", "age", 29, "addr", "Santa Fe, New Mexico", "weight", 1)
spmallette = graph.addVertex(T.label, "person", T.id, "spmallette", "name", "Stephen Mallette", "age", 0, "addr", "", "weight", 1)

tinkerpop = graph.addVertex(T.label, "software", "name", "TinkerPop", "lang", "java", "tag", "Graph computing framework", "weight", 1)
tinkergraph = graph.addVertex(T.label, "software", "name", "TinkerGraph", "lang", "java", "tag", "In-memory property graph", "weight", 1)
gremlin = graph.addVertex(T.label, "language", "name", "Gremlin", "lang", "groovy/python/javascript", "weight", 1)

okram.addEdge("created", tinkerpop, "weight", 1)
spmallette.addEdge("created", tinkerpop, "weight", 1)

okram.addEdge("knows", spmallette, "weight", 1)

tinkerpop.addEdge("define", gremlin, "weight", 1)
tinkerpop.addEdge("contains", tinkergraph, "weight", 1)
tinkergraph.addEdge("supports", gremlin, "weight", 1)

// Titan
dalaro = graph.addVertex(T.label, "person", T.id, "dalaro", "name", "Dan LaRocque ", "age", 0, "addr", "", "weight", 1)
mbroecheler = graph.addVertex(T.label, "person", T.id, "mbroecheler", "name", "Matthias Broecheler", "age", 29, "addr", "San Francisco", "weight", 1)

titan = graph.addVertex(T.label, "software", "name", "Titan", "lang", "java", "tag", "Graph Database", "weight", 1)

dalaro.addEdge("created", titan, "weight", 1)
mbroecheler.addEdge("created", titan, "weight", 1)
okram.addEdge("created", titan, "weight", 1)

dalaro.addEdge("knows", mbroecheler, "weight", 1)

titan.addEdge("implements", tinkerpop, "weight", 1)
titan.addEdge("supports", gremlin, "weight", 1)

// HugeGraph
javeme = graph.addVertex(T.label, "person", T.id, "javeme", "name", "Jermy Li", "age", 29, "addr", "Beijing", "weight", 1)
zhoney = graph.addVertex(T.label, "person", T.id, "zhoney", "name", "Zhoney Zhang", "age", 29, "addr", "Beijing", "weight", 1)
linary = graph.addVertex(T.label, "person", T.id, "linary", "name", "Linary Li", "age", 28, "addr", "Wuhan. Hubei", "weight", 1)

hugegraph = graph.addVertex(T.label, "software", "name", "HugeGraph", "lang", "java", "tag", "Graph Database", "weight", 1)

javeme.addEdge("created", hugegraph, "weight", 1)
zhoney.addEdge("created", hugegraph, "weight", 1)
linary.addEdge("created", hugegraph, "weight", 1)

javeme.addEdge("knows", zhoney, "weight", 1)
javeme.addEdge("knows", linary, "weight", 1)

hugegraph.addEdge("implements", tinkerpop, "weight", 1)
hugegraph.addEdge("supports", gremlin, "weight", 1)

點(diǎn)擊右上角的三角按鈕,這樣就創(chuàng)建出了一個(gè)圖茶袒。

圖查詢

在輸入框中輸入:

g.V()

就能查出上面創(chuàng)建的圖的所有頂點(diǎn)和邊梯刚。

TinkerPop關(guān)系圖

至此,執(zhí)行Gremlin的圖形化環(huán)境就已經(jīng)搭建完成薪寓,后續(xù)就可以做各種各樣炫酷的gremlin查詢了亡资。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市向叉,隨后出現(xiàn)的幾起案子锥腻,更是在濱河造成了極大的恐慌,老刑警劉巖母谎,帶你破解...
    沈念sama閱讀 211,290評(píng)論 6 491
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件旷太,死亡現(xiàn)場離奇詭異,居然都是意外死亡销睁,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,107評(píng)論 2 385
  • 文/潘曉璐 我一進(jìn)店門存崖,熙熙樓的掌柜王于貴愁眉苦臉地迎上來冻记,“玉大人,你說我怎么就攤上這事来惧∪呃酰” “怎么了?”我有些...
    開封第一講書人閱讀 156,872評(píng)論 0 347
  • 文/不壞的土叔 我叫張陵供搀,是天一觀的道長隅居。 經(jīng)常有香客問我,道長葛虐,這世上最難降的妖魔是什么胎源? 我笑而不...
    開封第一講書人閱讀 56,415評(píng)論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮屿脐,結(jié)果婚禮上涕蚤,老公的妹妹穿的比我還像新娘。我一直安慰自己的诵,他們只是感情好万栅,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,453評(píng)論 6 385
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著西疤,像睡著了一般烦粒。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上代赁,一...
    開封第一講書人閱讀 49,784評(píng)論 1 290
  • 那天扰她,我揣著相機(jī)與錄音兽掰,去河邊找鬼。 笑死义黎,一個(gè)胖子當(dāng)著我的面吹牛禾进,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播廉涕,決...
    沈念sama閱讀 38,927評(píng)論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼泻云,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了狐蜕?” 一聲冷哼從身側(cè)響起宠纯,我...
    開封第一講書人閱讀 37,691評(píng)論 0 266
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎层释,沒想到半個(gè)月后婆瓜,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,137評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡贡羔,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,472評(píng)論 2 326
  • 正文 我和宋清朗相戀三年廉白,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片乖寒。...
    茶點(diǎn)故事閱讀 38,622評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡猴蹂,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出楣嘁,到底是詐尸還是另有隱情磅轻,我是刑警寧澤,帶...
    沈念sama閱讀 34,289評(píng)論 4 329
  • 正文 年R本政府宣布逐虚,位于F島的核電站聋溜,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏叭爱。R本人自食惡果不足惜撮躁,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,887評(píng)論 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望买雾。 院中可真熱鬧馒胆,春花似錦、人聲如沸凝果。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,741評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽器净。三九已至型雳,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背纠俭。 一陣腳步聲響...
    開封第一講書人閱讀 31,977評(píng)論 1 265
  • 我被黑心中介騙來泰國打工沿量, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人冤荆。 一個(gè)月前我還...
    沈念sama閱讀 46,316評(píng)論 2 360
  • 正文 我出身青樓朴则,卻偏偏與公主長得像,于是被迫代替她去往敵國和親钓简。 傳聞我的和親對(duì)象是個(gè)殘疾皇子乌妒,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,490評(píng)論 2 348