Elasticsearch 使い方

実行環境

  • Elasticsearch 7.10.1
  • Kibana 7.10.1

    検索

完全一致検索

データ項目のタイプがキーワードとして登録されている必要があります。
検索対象のtypekeywordで、querytermを指定して行う必要があります。

request

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#対象index作成 都道府県(pref)のtypeを完全一致の対象にする為にkeywordで登録する
PUT search_job
{
"mappings" : {
"properties": {
"pref": {
"type": "keyword"
}
}
}
}

#type確認
GET search_job/_mapping

response

1
2
3
4
5
6
7
8
9
10
11
{
"search_job" : {
"mappings" : {
"properties" : {
"pref" : {
"type" : "keyword"
}
}
}
}
}

request

1
2
3
4
5
6
7
データ登録
POST /search_job/_doc
{
"pref" : "東京"
}
# データ確認
GET /search_job/_search

response

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
{
"took" : 1,
"timed_out" : false,
"_shards" : {
"total" : 1,
"successful" : 1,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : {
"value" : 1,
"relation" : "eq"
},
"max_score" : 1.0,
"hits" : [
{
"_index" : "search_job",
"_type" : "_doc",
"_id" : "jS17e3YB0KvFjllCp3-y",
"_score" : 1.0,
"_source" : {
"pref" : "東京"
}
}
]
}
}

request

1
2
3
4
5
6
7
8
9
# queryの種類をtermにすることで完全一致検索
GET /search_job/_search
{
"query" : {
"term": {
"pref":"東京"
}
}
}

response

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
{
"took" : 1,
"timed_out" : false,
"_shards" : {
"total" : 1,
"successful" : 1,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : {
"value" : 1,
"relation" : "eq"
},
"max_score" : 0.2876821,
"hits" : [
{
"_index" : "search_job",
"_type" : "_doc",
"_id" : "jS17e3YB0KvFjllCp3-y",
"_score" : 0.2876821,
"_source" : {
"pref" : "東京"
}
}
]
}
}

request

1
2
3
4
5
6
7
8
9
# queryの種類をtermにすることで完全一致検索
GET /search_job/_search
{
"query" : {
"term": {
"pref":"東"
}
}
}

response

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 該当するものは無い
{
"took" : 2,
"timed_out" : false,
"_shards" : {
"total" : 1,
"successful" : 1,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : {
"value" : 0,
"relation" : "eq"
},
"max_score" : null,
"hits" : [ ]
}
}

indexを定義せずにデータ登録した場合

request

1
2
3
4
POST /search_job2/_doc
{
"pref" : "東京"
}

response

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# typeでtextで登録されて、fieldsにtype:keywordでも登録されます
{
"search_job2" : {
"mappings" : {
"properties" : {
"pref" : {
"type" : "text",
"fields" : {
"keyword" : {
"type" : "keyword",
"ignore_above" : 256
}
}
}
}
}
}
}

request

1
2
3
4
5
6
7
8
9
# termの対象をpref.keywordとすることで、fieldsのtype:keywordを対象とすることができます
GET /search_job2/_search
{
"query" : {
"term" : {
"pref.keyword": "東京"
}
}
}

response

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
{
"took" : 1,
"timed_out" : false,
"_shards" : {
"total" : 1,
"successful" : 1,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : {
"value" : 1,
"relation" : "eq"
},
"max_score" : 0.2876821,
"hits" : [
{
"_index" : "search_job2",
"_type" : "_doc",
"_id" : "ki2Ne3YB0KvFjllCJX_C",
"_score" : 0.2876821,
"_source" : {
"pref" : "東京"
}
}
]
}
}

複数検索条件の完全一致

queryのboolmustで複数termを指定する

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
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
#request
PUT search_job3
{
"mappings" : {
"properties": {
"pref": {
"type": "keyword"
},
"employment": {
"type": "keyword"
}
}
}
}
#response
{
"acknowledged" : true,
"shards_acknowledged" : true,
"index" : "search_job3"
}
#request
GET search_job3/_mapping
#response
{
"search_job3" : {
"mappings" : {
"properties" : {
"employment" : {
"type" : "keyword"
},
"pref" : {
"type" : "keyword"
}
}
}
}
}
#request
POST /search_job3/_doc
{
"pref" : "東京",
"employment" : "full-time"
}
#response
{
"_index" : "search_job3",
"_type" : "_doc",
"_id" : "lS1OfXYB0KvFjllCZ3-D",
"_version" : 1,
"result" : "created",
"_shards" : {
"total" : 2,
"successful" : 1,
"failed" : 0
},
"_seq_no" : 0,
"_primary_term" : 1
}
#request
GET /search_job3/_search
#response
{
"took" : 484,
"timed_out" : false,
"_shards" : {
"total" : 1,
"successful" : 1,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : {
"value" : 1,
"relation" : "eq"
},
"max_score" : 1.0,
"hits" : [
{
"_index" : "search_job3",
"_type" : "_doc",
"_id" : "lS1OfXYB0KvFjllCZ3-D",
"_score" : 1.0,
"_source" : {
"pref" : "東京",
"employment" : "full-time"
}
}
]
}
}

#request
#複数検索条件の完全一致
GET /search_job3/_search
{
"query" : {
"bool": {
"must" : [
{
"term": {
"pref": "東京"
}
},
{
"term": {
"employment": "full-time"
}
}
]
}
}
}
#response
{
"took" : 2,
"timed_out" : false,
"_shards" : {
"total" : 1,
"successful" : 1,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : {
"value" : 1,
"relation" : "eq"
},
"max_score" : 0.5753642,
"hits" : [
{
"_index" : "search_job3",
"_type" : "_doc",
"_id" : "lS1OfXYB0KvFjllCZ3-D",
"_score" : 0.5753642,
"_source" : {
"pref" : "東京",
"employment" : "full-time"
}
}
]
}
}

ネストした検索対象への完全一致検索

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
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
#  路線が駅を持つようなネストしたデータを作成します
# request
PUT search_job4
{
"mappings" : {
"properties": {
"pref": {
"type": "keyword"
},
"employment": {
"type": "keyword"
},
"line": {
"properties" : {
"name": {
"type": "keyword"
},
"stations" : {
"properties" : {
"name" : {
"type" : "keyword"
}
}
}
}
}
}
}
}

POST /search_job4/_doc
{
"pref" : "東京",
"employment" : "full-time",
"line" : {
"name" : "山手線",
"stations" : [
{
"name" : "渋谷"
},
{
"name" : "恵比寿"
},
{
"name" : "品川"
}
]
}
}

GET /search_job4/_search

# response
# 路線が駅を持つようなネストしたデータが登録できました
{
"took" : 1,
"timed_out" : false,
"_shards" : {
"total" : 1,
"successful" : 1,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : {
"value" : 1,
"relation" : "eq"
},
"max_score" : 1.0,
"hits" : [
{
"_index" : "search_job4",
"_type" : "_doc",
"_id" : "li1_fXYB0KvFjllCmn_A",
"_score" : 1.0,
"_source" : {
"pref" : "東京",
"employment" : "full-time",
"line" : {
"name" : "山手線",
"stations" : [
{
"name" : "渋谷"
},
{
"name" : "恵比寿"
},
{
"name" : "品川"
}
]
}
}
}
]
}
}

# resquest
# ネストされている駅名に対して完全一致検索をします
GET /search_job4/_search
{
"query" : {
"term": {
"line.stations.name": "渋谷"
}
}
}

ネストした検索対象にネスト構造の経路の関係(Nested datatype)をもたせる

ネストした経路の関係(Nested datatype)を持たせたい場合にtypeにnested指定してmappingをします。

先程のmappingだと、何線の何駅かというのは検索できません。
下記のようなデータを追加した場合。
山手線の渋谷駅というデータを絞りこめません。

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
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
# request
POST /search_job4/_doc
{
"pref" : "東京",
"employment" : "full-time",
"line" : [
{
"name" : "東横線",
"stations" : [
{
"name" : "渋谷"
},
{
"name" : "中目黒"
},
{
"name" : "横浜"
}
]
},
{
"name" : "山手線",
"stations" : [
{
"name" : "東京"
},
{
"name" : "神田"
},
{
"name" : "浅草"
}
]
}
]
}

GET /search_job4/_search

# response
{
"took" : 2,
"timed_out" : false,
"_shards" : {
"total" : 1,
"successful" : 1,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : {
"value" : 2,
"relation" : "eq"
},
"max_score" : 1.0,
"hits" : [
{
"_index" : "search_job4",
"_type" : "_doc",
"_id" : "li1_fXYB0KvFjllCmn_A",
"_score" : 1.0,
"_source" : {
"pref" : "東京",
"employment" : "full-time",
"line" : {
"name" : "山手線",
"stations" : [
{
"name" : "渋谷"
},
{
"name" : "恵比寿"
},
{
"name" : "品川"
}
]
}
}
},
{
"_index" : "search_job4",
"_type" : "_doc",
"_id" : "mC2sfXYB0KvFjllCHn8N",
"_score" : 1.0,
"_source" : {
"pref" : "東京",
"employment" : "full-time",
"line" : [
{
"name" : "東横線",
"stations" : [
{
"name" : "渋谷"
},
{
"name" : "中目黒"
},
{
"name" : "横浜"
}
]
},
{
"name" : "山手線",
"stations" : [
{
"name" : "東京"
},
{
"name" : "神田"
},
{
"name" : "浅草"
}
]
}
]
}
}
]
}
}

# request
# 山手線の渋谷駅で検索
GET /search_job4/_search
{
"query" : {
"bool": {
"must" : [
{
"term": {
"line.name": "山手線"
}
},
{
"term": {
"line.stations.name": "渋谷"
}
}
]
}
}
}

# response
# 山手線の渋谷駅でないものも含まれてしまう。
{
"took" : 0,
"timed_out" : false,
"_shards" : {
"total" : 1,
"successful" : 1,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : {
"value" : 2,
"relation" : "eq"
},
"max_score" : 0.47851416,
"hits" : [
{
"_index" : "search_job4",
"_type" : "_doc",
"_id" : "li1_fXYB0KvFjllCmn_A",
"_score" : 0.47851416,
"_source" : {
"pref" : "東京",
"employment" : "full-time",
"line" : {
"name" : "山手線",
"stations" : [
{
"name" : "渋谷"
},
{
"name" : "恵比寿"
},
{
"name" : "品川"
}
]
}
}
},
{
"_index" : "search_job4",
"_type" : "_doc",
"_id" : "mC2sfXYB0KvFjllCHn8N",
"_score" : 0.47851416,
"_source" : {
"pref" : "東京",
"employment" : "full-time",
"line" : [
{
"name" : "東横線",
"stations" : [
{
"name" : "渋谷"
},
{
"name" : "中目黒"
},
{
"name" : "横浜"
}
]
},
{
"name" : "山手線",
"stations" : [
{
"name" : "東京"
},
{
"name" : "神田"
},
{
"name" : "浅草"
}
]
}
]
}
}
]
}
}

これは、追加したデータがElasticsearchの内部ではネスト構造を保たず、項目ごとにグルーピングされたような構造(Object datatype)で解釈される為になります。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
{
"line" : {
"name" : [
"東横線",
"山手線"
],
"stations" : {
"name" : [
"渋谷",
"中目黒",
"横浜",
"東京",
"神田",
"浅草"
]
}
}
}

路線のtypenestedにしてネスト構造を保ったままmappingし、ネスト構造の経路を指定して検索してみる。

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
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
# request
PUT search_job5
{
"mappings" : {
"properties": {
"pref": {
"type": "keyword"
},
"employment": {
"type": "keyword"
},
"line": {
"type" : "nested",
"properties" : {
"name": {
"type": "keyword"
},
"stations" : {
"properties" : {
"name" : {
"type" : "keyword"
}
}
}
}
}
}
}
}

GET search_job5/_mapping
# response
# line(路線)のtypeがnestedになっていることがわかる
{
"search_job5" : {
"mappings" : {
"properties" : {
"employment" : {
"type" : "keyword"
},
"line" : {
"type" : "nested",
"properties" : {
"name" : {
"type" : "keyword"
},
"stations" : {
"properties" : {
"name" : {
"type" : "keyword"
}
}
}
}
},
"pref" : {
"type" : "keyword"
}
}
}
}
}

# request
POST /search_job5/_doc
{
"pref" : "東京",
"employment" : "full-time",
"line" : {
"name" : "山手線",
"stations" : [
{
"name" : "渋谷"
},
{
"name" : "恵比寿"
},
{
"name" : "品川"
}
]
}
}

POST /search_job5/_doc
{
"pref" : "東京",
"employment" : "full-time",
"line" : [
{
"name" : "東横線",
"stations" : [
{
"name" : "渋谷"
},
{
"name" : "中目黒"
},
{
"name" : "横浜"
}
]
},
{
"name" : "山手線",
"stations" : [
{
"name" : "東京"
},
{
"name" : "神田"
},
{
"name" : "浅草"
}
]
}
]
}

GET /search_job5/_search
# response
{
"took" : 2,
"timed_out" : false,
"_shards" : {
"total" : 1,
"successful" : 1,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : {
"value" : 2,
"relation" : "eq"
},
"max_score" : 1.0,
"hits" : [
{
"_index" : "search_job5",
"_type" : "_doc",
"_id" : "mS3wfnYB0KvFjllCcn9x",
"_score" : 1.0,
"_source" : {
"pref" : "東京",
"employment" : "full-time",
"line" : {
"name" : "山手線",
"stations" : [
{
"name" : "渋谷"
},
{
"name" : "恵比寿"
},
{
"name" : "品川"
}
]
}
}
},
{
"_index" : "search_job5",
"_type" : "_doc",
"_id" : "mi3wfnYB0KvFjllCk3_f",
"_score" : 1.0,
"_source" : {
"pref" : "東京",
"employment" : "full-time",
"line" : [
{
"name" : "東横線",
"stations" : [
{
"name" : "渋谷"
},
{
"name" : "中目黒"
},
{
"name" : "横浜"
}
]
},
{
"name" : "山手線",
"stations" : [
{
"name" : "東京"
},
{
"name" : "神田"
},
{
"name" : "浅草"
}
]
}
]
}
}
]
}
}

# request
# nestedのpathにlineを指定し、line(路線)のネスト構造の経路内で山手線の渋谷を検索する
GET /search_job5/_search
{
"query": {
"nested": {
"path": "line",
"query" : {
"bool": {
"must" : [
{
"term": {
"line.name": "山手線"
}
},
{
"term": {
"line.stations.name": "渋谷"
}
}
]
}
}
}
}
}

# response
{
"took" : 4,
"timed_out" : false,
"_shards" : {
"total" : 1,
"successful" : 1,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : {
"value" : 1,
"relation" : "eq"
},
"max_score" : 1.1162586,
"hits" : [
{
"_index" : "search_job5",
"_type" : "_doc",
"_id" : "mS3wfnYB0KvFjllCcn9x",
"_score" : 1.1162586,
"_source" : {
"pref" : "東京",
"employment" : "full-time",
"line" : {
"name" : "山手線",
"stations" : [
{
"name" : "渋谷"
},
{
"name" : "恵比寿"
},
{
"name" : "品川"
}
]
}
}
}
]
}
}

参考url

core dumpについて

php-fpmのログで下記のようなSIGSEGVのエラーがでており、原因を調査する場合にcore dumpという方法があるようなので試してみました。

1
WARNING: [pool www] child 17248 exited on signal 11 (SIGSEGV)

検証環境

CentOS8

core dumpとは

システムが異常終了した場合に、その時点のメモリの内容を記録したcoreファイルを吐き出すことを指すようです。

coreファイルの出力先を確認

1
2
$ cat /proc/sys/kernel/core_pattern
core

coreとなっている場合、
プロセスの作業ディレクトリに作成されます。
プロセスの作業ディレクトリは、
ls -l /proc/{プロセスID}/cwd のリンク先になります。
プロセスが終了すると /proc/{プロセスID} のディレクトリは無くなるので、
確認する場合はプロセスが生きている間に確認する必要があります。
プロセスを生きている間に確認することが難しい場合は、
/proc/sys/kernel/core_patternに適当なディレクトリを作成することでcoreの出力先を指定できます。
osを再起動すると元の設定にもどります。

1
echo '/tmp/core-%e-%p' > /proc/sys/kernel/core_pattern

%eは、プログラム名。%pはプロセスIDとして置き換わります。

CentOS8の場合

1
2
$ cat /proc/sys/kernel/core_pattern
|/usr/lib/systemd/systemd-coredump %P %u %g %s %t %c %h %e

となっており、パイブでわたされた、/usr/lib/systemd/systemd-coredumpが
/var/lib/systemd/coredumpのディレクトリ直下にコアダンプが出力されるようになっていました。
また、coredumpctlでcoreの情報を見たりできます。

最近作成されたcoreの一覧を表示。

1
2
3
$ coredumpctl list
TIME PID UID GID SIG COREFILE EXE
Sun 2020-12-06 22:29:22 JST 3252 1000 1000 11 present /usr/bin/bash

coredumpctl info に pidを指定して情報を見る。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
$ coredumpctl info 3252
PID: 3252 (segv.sh)
UID: 1000 (unamu)
GID: 1000 (unamu)
Signal: 11 (SEGV)
Timestamp: Sun 2020-12-06 22:29:21 JST (6min ago)
Command Line: /bin/bash ./segv.sh
Executable: /usr/bin/bash
Control Group: /user.slice/user-1000.slice/user@1000.service/gnome-terminal-server.service
Unit: user@1000.service
User Unit: gnome-terminal-server.service
Slice: user-1000.slice
Owner UID: 1000 (unamu)
Boot ID: 35a2b597dc5a4a6ebe37fd3a7e97bd73
Machine ID: c4f822f021d5433ab143f054bca5b672
Hostname: localhost.localdomain
Storage: /var/lib/systemd/coredump/core.segv\x2esh.1000.35a2b597dc5a4a6ebe37fd3a7e97bd73.3252.1607261361000000.lz4
Message: Process 3252 (segv.sh) of user 1000 dumped core.

Stack trace of thread 3252:
#0 0x00007fe849946d79 _int_malloc (libc.so.6)
#1 0x00007fe84994850e malloc (libc.so.6)
#2 0x00005625a34934c2 xmalloc (bash)

coreファイルのファイルサイズの変更

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
$ cat /proc/self/limits
Limit Soft Limit Hard Limit Units
Max cpu time unlimited unlimited seconds
Max file size unlimited unlimited bytes
Max data size unlimited unlimited bytes
Max stack size 8388608 unlimited bytes
Max core file size unlimited unlimited bytes
Max resident set unlimited unlimited bytes
Max processes 3140 3140 processes
Max open files 1024 262144 files
Max locked memory 65536 65536 bytes
Max address space unlimited unlimited bytes
Max file locks unlimited unlimited locks
Max pending signals 3140 3140 signals
Max msgqueue size 819200 819200 bytes
Max nice priority 0 0
Max realtime priority 0 0
Max realtime timeout unlimited unlimited us

の Max core file size の項目がCoreファイルサイズの設定になります。
softlimitが0だとcoreファイルが作成されません。

unlimitedに設定すると上限なしで作成してくれます。

1
$ ulimit -c unlimited

OSを再起動すると元の設定値に戻ります。

SIGSEGVエラーを出して、coreファイルが作成されている確認する

下記のシェルスクリプトを実行して、SIGSEGVエラーを出す。

segv.sh

1
2
3
4
5
#!/bin/bash
function func {
func
}
func
1
2
3
4
# ./segv.sh 
Segmentation fault (コアダンプ)
# ls /tmp
core-segv.sh-41856

(コアダンプ)と表示されて出力を指定した先にcoreファイルが作成されています。

coreファイルの中身を確認

gdb 実行プログラミング coreファイル でgdbでデバックできます。

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
# gdb /bin/bash /tmp/core-segv.sh-41856

GNU gdb (GDB) Red Hat Enterprise Linux 8.2-11.el8
Copyright (C) 2018 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Type "show copying" and "show warranty" for details.
This GDB was configured as "x86_64-redhat-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.

For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from /bin/bash...Reading symbols from .gnu_debugdata for /usr/bin/bash...(no debugging symbols found)...done.
(no debugging symbols found)...done.

warning: core file may not match specified executable file.
[New LWP 41856]

warning: Loadable section ".note.gnu.property" outside of ELF segments
Core was generated by `/bin/bash ./segv.sh'.
Program terminated with signal SIGSEGV, Segmentation fault.
#0 0x000055b592ffb6db in expand_word_list_internal ()
Missing separate debuginfos, use: yum debuginfo-install bash-4.4.19-10.el8.x86_64
(gdb)

gdbの対話モードになったら bt or backtrackでコアダンプされる前の状態をさかのぼって原因を調査できます。

1
2
3
4
5
6
7
8
9
10
11
(gdb) bt
#0 0x000055b592ffb6db in expand_word_list_internal ()
#1 0x000055b592fd2fa7 in execute_simple_command ()
#2 0x000055b592fd51a6 in execute_command_internal ()
#3 0x000055b592fd4ab5 in execute_command_internal ()
#4 0x000055b592fd7a79 in execute_function.isra ()
#5 0x000055b592fd4124 in execute_simple_command ()
#6 0x000055b592fd51a6 in execute_command_internal ()
#7 0x000055b592fd4ab5 in execute_command_internal ()
#8 0x000055b592fd7a79 in execute_function.isra ()
#9 0x000055b592fd4124 in execute_simple_command ()

参考url

https://www2.filewo.net/wordpress/2019/12/16/centos%E3%81%A7%E3%81%AF%E3%83%87%E3%83%95%E3%82%A9%E3%83%AB%E3%83%88%E3%81%A7%E3%82%B3%E3%82%A2%E3%83%80%E3%83%B3%E3%83%97%E3%81%8C%E5%90%90%E3%81%8B%E3%82%8C%E3%81%AA%E3%81%84%E3%81%AE%E3%81%A7/

https://rabbitfoot141.hatenablog.com/entry/2016/11/14/153101

https://rheb.hatenablog.com/entry/systemd-coredump

https://qiita.com/suzutsuki0220/items/aa84d7e2e8f37e867f3d

https://qiita.com/rarul/items/d33b664c8414f065e65e

php-fpm

https://www.bit-hive.com/articles/20190206

AWS EKS にnginxのPodをデプロイしてブラウザからアクセスする

Docker/Kubernetes実践コンテナ開発入門の本を読んでいて5.10.1のIngressを通じたアクセスをAmazon EKSで行う場合はどのようになるのか調べました。

利用しているdocker image

gihyodocker/echo : Hollo Docker!!と表示するwebサーバー
gihyodocker/nginx-proxy : echoに対してリバースプロキシする

手順

ReplicaSet

同じ仕様のPodを複数作成する

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
apiVersion: apps/v1
kind: ReplicaSet
metadata:
name: echo-summer
labels:
app: echo
release: summer
spec:
replicas: 2
selector:
matchLabels:
app: echo
release: summer
template:
metadata:
labels:
app: echo
release: summer
spec:
containers:
- name: nginx
image: gihyodocker/nginx:latest
env:
- name: BACKEND_HOST
value: localhost:8080
ports:
- containerPort: 80
- name: echo
image: gihyodocker/echo:latest
ports:
- containerPort: 8080

Service

Podの集合に対して、アクセス経路を作成する。typeをNodePortにすることでグローバルなポートを開ける。OSI参照モデルのレイヤー4までしか扱えない。

1
2
3
4
5
6
7
8
9
10
11
12
13
apiVersion: v1
kind: Service
metadata:
name: "echo"
spec:
type: NodePort
selector:
app: echo
release: summer
ports:
- port: 80
targetPort: 80
protocol: TCP

Ingress

ServiceのKudernetesクラスタ外への公開。
VirtualHostやパスベースでのHTTP、HTTPSベースでのルーティングが可能。
Ingressが作成されると、EKSのALB Ingress ControllerがALBと必要なAWSサポートリソースを作成してくれる。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: "echo"
annotations:
kubernetes.io/ingress.class: alb # Ingress が ALB Ingress Controllerを使用することを設定
alb.ingress.kubernetes.io/scheme: internet-facing
alb.ingress.kubernetes.io/target-type: ip # Serviceでアクセス経路が作成されたPodにトラフィックをルーティングすることを設定
labels:
app: echo
spec:
rules:
- http:
paths:
- path: /*
backend:
serviceName: "echo"
servicePort: 80

AWS EKS にてno endpoints available for service kubernetes-dashboardのエラー対応

エラーの出た場面

AWSのチュートリアル: Kubernetes ダッシュボード (ウェブ UI) のデプロイをやっている時に、
「ウェブブラウザで以下のリンクを開いて、ダッシュボードエンドポイントにアクセスします。」という段階で下記urlにアクセスすると
http://localhost:8001/api/v1/namespaces/kubernetes-dashboard/services/https:kubernetes-dashboard:/proxy/#!/login

下記のエラーが画面に表示されダッシュボードエンドポイントにアクセスできなかった。

1
2
3
4
5
6
7
8
9
{
kind: "Status",
apiVersion: "v1",
metadata: { },
status: "Failure",
message: "no endpoints available for service "kubernetes-dashboard"",
reason: "ServiceUnavailable",
code: 503
}

対応方法

下記のコマンドを打って、Namespace kubernetes-dashboard を対象とするFargateプロファイルを追加で作成する。

1
2
3
4
eksctl create fargateprofile \
--name fp-kubernetes-dashboard \
--namespace kubernetes-dashboard \
--cluster {クラスター名}

エラーの理由

https://dev.classmethod.jp/articles/fargate-for-eks-tutorial-kubernetes-dashboard/#toc-4
の「「Fargate for EKS」の場合に必要な追加手順」項目を参照

python moduleのimport fromのルートとなる起点を指定したい

実行スクリプトのディレクトリ階層に関係なくfrom importをさせたい

pythonを実行するスクリプトのディレクトリ階層によってfrom importが失敗することがあります。
実行するスクリプトのディレクトリ階層の位置に関係なくfrom importをできるようにする方法を調べました。

このようなディレクトリ構成で普段は、python main.pyからitem_service.py item.py が呼び出され実行される内容だとします。

1
2
3
4
5
├── main.py
├── models
│   └── item.py
└──services
   └── item_service.py

下記のようにitem_service.pyはmain.pyをルートとしてmodels/item.pyをfrom importしています。

1
2
3
4
5
6
7
8
9
10
item_service.py

from models.item import Item

class ItemServiceModel:
def search():
...

if __name__ == '__main__':
ItemServiceModel.search()

この場合に python item_service.py をすると
ModuleNotFoundError: No module named ‘models’
のようなエラーが出てimportに失敗します。

なぜ失敗するか

https://docs.python.org/ja/3/tutorial/modules.html
html#the-module-search-path
公式ドキュメントによると、「入力されたスクリプトのあるディレクトリ」がモジュールの探索パスになるということです。
python main.pyでは成功し、python item_service.pyでは失敗するようになることの理解はできました。

入力されたスクリプトのあるディレクトリ構成位置に関係なくfrom importさせたい

先程の公式ドキュメントの同じところに
「PYTHONPATH (ディレクトリ名のリスト。シェル変数の PATH と同じ構文)。」がモジュールの探索パス(import from の起点ルート)になると書いています。
なので、.zshrc や .bshrc に

1
export PYTHONPATH=$PYTHONPATH:{main.pyのあるディレクトリの絶対パス}

とすれば、python item_service.pyでもfrom importが成功するようになりました。

python リスト内の*について

1
2
3
4
5
6
7
8
9
10
def test(x):
return x * 2


a = [[3,2,1],[5,4,6],[5,4,6]]
a = [*map(lambda x: test(x), a)]
print(a)

# print出力
[[3, 2, 1, 3, 2, 1], [5, 4, 6, 5, 4, 6], [5, 4, 6, 5, 4, 6]]

このようなコードがあって、[*map(の部分が何をしているのか分からなかったので調べました。

結論

map()の返り値のリストを引数展開して、リストを定義している。

詳細

リストの前に*をつけると引数展開される

1
2
3
print(*[1, 2, 3])
# print出力
1 2 3

参考url

http://pixelbeat.jp/variable_length_arguments_and_argument_unpacking/

他の [ ]系 の変則的な書き方

Numpy Boolean Index

Numpy arrayのIndexにBooleanのリストを渡すと、リストのTrueの位置と一致する値だけにできる。

1
2
3
4
5
6
import numpy as np
test = np.array([1000, 2000, None])
print(test[[False, True, True]])

# print出力
[2000 None]

参考url

https://qiita.com/junjis0203/items/4136f9ae4f07c452ceb6#boolean-index%E3%81%A8%E5%80%A4%E8%A8%AD%E5%AE%9A

コマンドラインインターフェイスのオプションについて

コマンドラインでオプションの引数を指定する時に、半角スペース=を利用する違いについて気になったので調べました。

調査結果

オプションの引数が省略できる場合だと半角スペースが、オプション引数を省略した形かコマンドの引数か曖昧なので=の指定が必要。

詳細内容

コマンドラインアプリケーションごとに違いはありますので grep を基準にします。

まずファイルを作成します。

1
2
3
4
5
6
7
cat > test.txt
test
hoge
poyo
poke
111
control+d

man grep をすると、–after-context=num でnum行分を一致した行以降も表示しれくれるとなっています。

1
2
-A num, --after-context=num
Print num lines of trailing context after each match. See also the -B and -C options.
1
2
3
4
5
~/Desktop ❯❯❯ grep test test.txt --after-context=3
test
hoge
poyo
poke
1
2
3
4
5
~/Desktop ❯❯❯ grep test test.txt --after-context 3
test
hoge
poyo
poke

–after-context=num 、–after-contextnum のどちらでも受け付けてくれます。

man grep をすると、–colour=never で一致した箇所の色付けを消してくれるとなっています。[when]になっているのでオプションの引数は省略できます。

1
2
3
--colour=[when, --color=[when]]
Mark up the matching text with the expression stored in GREP_COLOR environment variable. The possible
values of when can be `never', `always' or `auto'.
1
2
~/Desktop ❯❯❯ grep test test.txt --colour=never
test
1
2
3
~/Desktop ❯❯❯ grep test test.txt --colour never
test.txt:test
grep: never: No such file or directory
1
2
~/Desktop ❯❯❯ grep test --colour test.txt
test

–colour=never は受け付けてくれますが、–colournever はneverがオプションの引数とは認識されずに検索対象のファイル名と認識されました。
確かにオプションの引数が省略できる場合だとそれが、オプションの引数かコマンドの引数か曖昧なので=の指定が必要なことは納得できますね。

参考url

http://docopt.org/ : -o --option の項目
https://qiita.com/rubytomato@github/items/2ee2fd4127eadc1f1193
https://qiita.com/aosho235/items/0f2b73d08eb645c05208

This version of ChromeDriver only supports Chrome version {vesion番号}

エラー This version of ChromeDriver only supports Chrome version 〇〇

SeleniumのWebdriverでChromeを動かしているとThis version of ChromeDriver only supports Chrome version 81とエラーメッセージが表示されました。
chromeのバージョンが自動アップデートされて、webdriverとchromeのバージョンが合わなくなったので表示されたようです。
ですので普段利用するchromeとは別に、seleniumで利用するchromeをインストールしてchromeの自動アップデートを無効にする方法を調べたのですが、個別にアップデートを抑制する方法が見つからず。

ChromiunだとChromeと同じ機能で自動アップデートされない

そんな時に、ChromiumだとChromeとほぼ同じ機能で自動アップデートされないという情報を見つけたので、
Webdriverのversionに対応する、Chromiumをダウンロードして解決しました。

Chromiumの過去バージョンのダウンロードurl

https://chromium.woolyss.com/

GoogleIME変換候補登録

GoogleIMEで「餘根津」という旧字体を含んでいたり特殊な名字を「よねず」から変換しようとしても
候補には「米津」とか「米酢」しかでてこないと思います。
それがよく利用する単語なのに変換ででてこないと面倒ですよね。
そんな時の解決方法としてGoogleIME単語登録があります。
変換候補の単語を登録すると、変換候補に出てくるようになります。

CQRSとマテリアライズドビュー

検索の一覧ページでパフォーマンスが問題になることがありますが、
マテリアライズドビューを利用することでパフォーマンス改善ができます。
mysqlではマテリアライズドビューの機能が無いので、
マテリアライズドビューのようなSQL結果を保存するテーブルを作成し、CQRSで更新をおこない利用することでパフォーマンスを改善することができます。

(例)SNSでユーザーに多くの投稿があって最新の投稿内容について検索内容が一致するユーザーを一覧で表示する場合に、
マテリアライズドビューをユーザーと最新の投稿の中間テーブルとすると
下記のような最新の投稿を特定するクエリが必要なくなることでパフォーマンス改善になる。

1
left join posts as p2 on posts.created_at < p2.created_at where p2.id is null

CQRS マテリアライズドビュー 更新フロー図
CQRSとマテリアライズドビューの更新フロー図

参考url

https://slideship.com/users/@miyake/presentations/2018/04/5JgW9hp3kHDDZi6zzDRxbm/?p=8
http://nippondanji.blogspot.com/2015/06/rdb.html
https://blog.spacemarket.com/code/room-search-speed/
https://docs.microsoft.com/ja-jp/azure/architecture/patterns/materialized-view
http://qcontokyo.com/data_2016/pdf/B-2_2_JunichiKato.pdf

https://docs.microsoft.com/ja-jp/azure/architecture/patterns/materialized-view

Laravel で参考のコードを書いてみました。

https://github.com/unamu1229/sampleapp/commit/948a6a6809ecf421629ddf18ca54bef44195e94c

処理の流れ

CommandSelectionエンティティ(コマンド用エンティティ)が CommandSelectionRepositoryリポジトリ(コマンド用リポジトリ)で永続化される

CommandSelectionRepositoryリポジトリがイベントを発生させる(新規作成時:PushCommandSelection 更新時:PutCommandSelection)
※ドメインイベントではないので、リポジトリでイベントを発生させてよいのではないかと思いました。
識別子からクエリ用のエンティティを作成する時も永続化されてからでなければ、最新の状態をとってこれないこともありますし。

リスナーでイベントを受ける(イベントPushCommandSelectionの場合、PushQuerySelection。イベントPutCommandSelectionの場合、PutQuerySelection。)

リスナーがQuerySelectionエンティティ(クエリ用のエンティティ)を作成し、QuerySelectionRepositoryリポジトリ(クエリ用リポジトリ)でマテリアライズドビュー的な永続化を行う。