Skip to content

Commit 9d23340

Browse files
authored
Merge pull request #464 from AlisProject/add_bcg_ranking
Add search tags count.
2 parents db4f589 + b60a95e commit 9d23340

File tree

8 files changed

+396
-1
lines changed

8 files changed

+396
-1
lines changed

function02-template.yaml

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -311,6 +311,23 @@ Resources:
311311
Timeout: 15
312312
TracingConfig:
313313
Mode: "Active"
314+
SearchTagsCount:
315+
Type: "AWS::Lambda::Function"
316+
Properties:
317+
Code: ./deploy/search_tags_count.zip
318+
Environment:
319+
Variables:
320+
ELASTIC_SEARCH_ENDPOINT: !Ref ElasticSearchEndpoint
321+
Handler: handler.lambda_handler
322+
MemorySize: 3008
323+
Role:
324+
Fn::ImportValue:
325+
Fn::Sub: "${AlisAppId}-LambdaRole"
326+
Runtime: python3.6
327+
Timeout: 300
328+
TracingConfig:
329+
Mode: "Active"
330+
314331

315332
Outputs:
316333
ArticleSupportersIndex:
@@ -373,3 +390,7 @@ Outputs:
373390
Value: !GetAtt TopicsCryptoRankingIndex.Arn
374391
Export:
375392
Name: !Sub "${AlisAppId}-TopicsCryptoRankingIndex"
393+
SearchTagsCount:
394+
Value: !GetAtt SearchTagsCount.Arn
395+
Export:
396+
Name: !Sub "${AlisAppId}-SearchTagsCount"

permission-template.yaml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -323,3 +323,12 @@ Resources:
323323
Fn::Sub: "${AlisAppId}-TopicsCryptoRankingIndex"
324324
Principal: "apigateway.amazonaws.com"
325325
SourceArn: !Sub ${RestApiArn}/*/GET/topics/crypto/ranking
326+
SearchTagsCountApiGatewayInvoke:
327+
Type: "AWS::Lambda::Permission"
328+
Properties:
329+
Action: "lambda:InvokeFunction"
330+
FunctionName:
331+
Fn::ImportValue:
332+
Fn::Sub: "${AlisAppId}-SearchTagsCount"
333+
Principal: "apigateway.amazonaws.com"
334+
SourceArn: !Sub ${RestApiArn}/*/GET/search/tags_count

src/common/es_util.py

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
# -*- coding: utf-8 -*-
22
import settings
33
import os
4+
import time
45

56

67
class ESUtil:
@@ -38,6 +39,35 @@ def search_tag(elasticsearch, word, limit, page):
3839

3940
return tags
4041

42+
@staticmethod
43+
def search_tags_count(elasticsearch, size=500, term=604800):
44+
from_time = round(time.time()) - term
45+
body = {
46+
'size': 0,
47+
'query': {
48+
'bool': {
49+
'must': [
50+
{'range': {'published_at': {'gte': from_time}}}
51+
]
52+
}
53+
},
54+
'aggs': {
55+
'tags_count': {
56+
'terms': {
57+
'field': 'tags.keyword',
58+
'order': {'_count': 'desc'},
59+
'size': size
60+
}
61+
}
62+
}
63+
}
64+
65+
response = elasticsearch.search(
66+
index='articles',
67+
body=body
68+
)
69+
return response['aggregations']['tags_count']['buckets']
70+
4171
@staticmethod
4272
def search_article(elasticsearch, limit, page, word=None, tag=None):
4373
body = {

src/common/settings.py

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,15 @@
150150
},
151151
'maxItems': 5
152152
},
153+
'tags_count': {
154+
'type': 'array',
155+
'items': {
156+
'type': 'string',
157+
'minLength': 1,
158+
'maxLength': 25
159+
},
160+
'maxItems': 150
161+
},
153162
'tip_value': {
154163
'type': 'number',
155164
'minimum': 1,
@@ -274,7 +283,12 @@
274283
},
275284
'pin_code': {
276285
'type': 'string'
277-
}
286+
},
287+
'tags_count_search_days': {
288+
'type': 'integer',
289+
'minimum': 1,
290+
'maximum': 10000
291+
},
278292
}
279293

280294
# ログに出力されてはいけないパラメータ(ログ出力時に値がマスクされる)
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import os
2+
from search_tags_count import SearchTagsCount
3+
from elasticsearch import Elasticsearch, RequestsHttpConnection
4+
from requests_aws4auth import AWS4Auth
5+
6+
awsauth = AWS4Auth(
7+
os.environ['AWS_ACCESS_KEY_ID'],
8+
os.environ['AWS_SECRET_ACCESS_KEY'],
9+
os.environ['AWS_REGION'],
10+
'es',
11+
session_token=os.environ['AWS_SESSION_TOKEN']
12+
)
13+
elasticsearch = Elasticsearch(
14+
hosts=[{'host': os.environ['ELASTIC_SEARCH_ENDPOINT'], 'port': 443}],
15+
http_auth=awsauth,
16+
use_ssl=True,
17+
verify_certs=True,
18+
connection_class=RequestsHttpConnection
19+
)
20+
21+
22+
def lambda_handler(event, context):
23+
search_tags_count = SearchTagsCount(event, context, elasticsearch=elasticsearch)
24+
return search_tags_count.main()
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
import json
2+
3+
from jsonschema import validate
4+
5+
import settings
6+
from decimal_encoder import DecimalEncoder
7+
from es_util import ESUtil
8+
from lambda_base import LambdaBase
9+
from parameter_util import ParameterUtil
10+
11+
12+
class SearchTagsCount(LambdaBase):
13+
def get_schema(self):
14+
return {
15+
'type': 'object',
16+
'properties': {
17+
'tags': settings.parameters['tags_count'],
18+
'search_days': settings.parameters['tags_count_search_days']
19+
},
20+
'required': ['tags']
21+
}
22+
23+
def validate_params(self):
24+
ParameterUtil.cast_parameter_to_int(self.params, self.get_schema())
25+
self.params['tags'] = self.event['multiValueQueryStringParameters'].get('tags')
26+
validate(self.params, self.get_schema())
27+
28+
def exec_main_proc(self):
29+
# 直近1週間分のタグを集計
30+
search_size = len(self.params['tags']) * settings.parameters['tags']['maxItems']
31+
search_days = self.params.get('search_days') if self.params.get('search_days') else 7
32+
from_time = 86400 * search_days
33+
search_result = ESUtil.search_tags_count(self.elasticsearch, search_size, from_time)
34+
35+
# 集計結果より指定タグの件数を取得
36+
temp = []
37+
for tag in self.params['tags']:
38+
tag_count = [d['doc_count'] for d in search_result if d['key'] == tag]
39+
temp.append({
40+
'tag': tag,
41+
'count': tag_count[0] if len(tag_count) > 0 else 0
42+
})
43+
result = sorted(temp, key=lambda x: x['count'], reverse=True)
44+
return {
45+
'statusCode': 200,
46+
'body': json.dumps(result, cls=DecimalEncoder)
47+
}

swagger/swagger.yaml

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -256,6 +256,13 @@ definitions:
256256
type: integer
257257
created_at:
258258
type: integer
259+
TagCount:
260+
type: object
261+
properties:
262+
tag:
263+
type: string
264+
count:
265+
type: integer
259266
Fraud:
260267
type: object
261268
properties:
@@ -498,6 +505,43 @@ paths:
498505
passthroughBehavior: when_no_templates
499506
httpMethod: POST
500507
type: aws_proxy
508+
/search/tags_count:
509+
get:
510+
description: "タグ件数検索"
511+
parameters:
512+
- name: "tags"
513+
in: "query"
514+
description: "検索タグ"
515+
required: true
516+
type: array
517+
items:
518+
type: string
519+
- name: "search_days"
520+
in: "query"
521+
description: "検索対象の日数"
522+
required: false
523+
type: "integer"
524+
responses:
525+
"200":
526+
description: "タグ件数一覧"
527+
schema:
528+
type: array
529+
items:
530+
$ref: '#/definitions/TagCount'
531+
x-amazon-apigateway-integration:
532+
responses:
533+
default:
534+
statusCode: "200"
535+
uri:
536+
Fn::Join:
537+
- ''
538+
- - Fn::Sub: "arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/"
539+
- Fn::ImportValue:
540+
Fn::Sub: "${AlisAppId}-SearchTagsCount"
541+
- "/invocations"
542+
passthroughBehavior: when_no_templates
543+
httpMethod: POST
544+
type: aws_proxy
501545
/articles/recent:
502546
get:
503547
description: "最新記事一覧情報を取得"

0 commit comments

Comments
 (0)