見出し画像

複数のデータソースを管理する方法

こんにちは!
Airitechのビッグデータ・AI活用グループのドゥックです。

この記事では、複数のデータソースを管理する方法について書きたいと思います。

1. 複数なデータソースとは?

データソースというのは、データを保存したり取得したりするものです。

例えば:MySQL、Elasticsearch、Redis、APIなど、2つ以上のデータソースを複数なデータソースと言います。

2. 背景

ここでは、3つのデータソースを扱ってみます。

MySQL、Elasticsearch、Redisです。2つの設計方法で、MySQLとElasticsearchの情報を取得して、Redisに書き込んでみましょう。

データ構成は、次のとおりです。

画像1

※上記の図では、属性ごとに色分けしています。

※説明コード言語は、Pythonです。

設計1 : データソースごとにクラスを割り当てる

データソースに応じて、専用クラスを作成します。

画像3

Redisに書き込む流れは、次のとおりです。

   # MySQLの情報: mysql_result = {"username": "Duc", "user_email": "trieuduc1996@gmail.com"}
   # MysqlStudentオブジェクト化
1. mysql_student = MySqlStudent(**mysql_result)
   # mysql_studentのuser_emailを基にElasticsearchで検索します
   # Elasticsearchの情報: es_result = {"email": "trieuduc1996@gmail.com", "computer_name": "pc1"}
   # EsStudentオブジェクト化
2. es_student = EsStudent(**es_result)
   # RedisStudentオブジェクトを作成
3. RedisStudent(name=mysql_student.username,
                email=mysql_student.user_email,
                pc_name=es_student.computer_name)

設計1の問題
1. RedisStudentオブジェクトを作成するとき、属性を一個ずつ割り当てなければならないです。
2. データソース変更や属性の追加があると、影響が大きいです。

※説明コード言語は、Pythonです。

次の設計で、解決してみましょう!

設計2 : コンバータ(Converter)

設計2は、設計1と似ていますが、コンバータで属性が一括変換できます。

画像4

やり方は、後ほど説明します。まず、コンバータを使ったらどうなるかを説明します。

   # MySQLの情報: mysql_result = {"username": "Duc", "user_email": "trieuduc1996@gmail.com"}
   # MysqlStudentオブジェクト化
1. mysql_student = MySqlStudent(**mysql_result)
   # mysql_studentのuser_emailを基にElasticsearchで検索します
   # Elasticsearchの情報: es_result = {"email": "trieuduc1996@gmail.com", "computer_name": "pc1"}
   # EsStudentオブジェクト化
2. es_student = EsStudent(**es_result)
   # RedisStudentオブジェクトを作成
3.	converter = Converter()
4.	converter.add(mysql_student)
5.	converter.add(es_student)
6.	redis_student = converter.export(RedisStudent)

設計2は、設計1のステップ2まで同じですが、設計1のステップ3における属性を、一個ずつ割り当てる必要がありません。

設計2の解説

画像4

上記のとおり、2つの部分から構成されています。

1. MAPPING クラス属性
データクラスに追加するDictionary(クラス属性)です。役割は、属性名を標準すれば何になるかと定義します。MAPPINGは{クラスの属性名:標準化名}というペアを保存します。

2. Converterクラス
Dictionaryとadd関数とexport関数を含めます。Dictionaryで{標準化名:インプットの値(mysql_student.usernameとか)}というペアを保存します。

Add関数が呼ばれると、インプットのMAPPINGでデータを変換して、Dictionaryに書き込みます。Export関数が呼ばれると、アウトプットのMAPPINGで、Dictionaryのデータを変換してオブジェクト化します。

Converterクラスは次のとおりです。

class Converter:
	def __init__(self):
		self.standardized_data = {}

	def add(self, datasource):
		for field_name, field_value in datasource.__dict__.items():
			standardized_field_name = datasource.MAPPING.get(field_name)
			if standardized_field_name:
				self.standardized_data[standardized_field_name] = field_value

	def export(self, targetClass):
		localized_data = {}
		for localized_field_name, standardized_field_name in targetClass.MAPPING.items():
			localized_data[localized_field_name] = self.standardized_data.get(standardized_field_name)
		return targetClass(**localized_data)

設計1の問題が解決できました。データソースごとに事前定義MAPPING を確定すれば、自動的に変換できます。データソースと属性を追加したり外したりしても、影響が小さいと思います。

しかし、この設計を使用するとき弱点も感じていました。

1. 柔軟すぎるので、converterで保存している値は何か曖昧です。
2. 1-n対応が不便です。
3. データソースの順序がなければ、手動で対応しないといけません。

実行できるサンプルも投稿しました。ぜひご覧ください。

最後までお読みいただきありがとうございました。

Airitech株式会社について
システムのトラブルシュートや性能改善/ビッグデータの活用/システム開発支援を主な事業とし、ITシステムのダウンや性能劣化など、難度の高い問題の解決をしています。その実績を活かして、お客様の環境に合わせたシステムの導入と保守サービスの提案を広く行っています。

採用情報はこちら



この記事が気に入ったらサポートをしてみませんか?