bda-practicals 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- bda_practicals-0.1.0/LICENSE +21 -0
- bda_practicals-0.1.0/MANIFEST.in +2 -0
- bda_practicals-0.1.0/PKG-INFO +71 -0
- bda_practicals-0.1.0/README.md +48 -0
- bda_practicals-0.1.0/bda/__init__.py +13 -0
- bda_practicals-0.1.0/bda/__main__.py +4 -0
- bda_practicals-0.1.0/bda_package/__init__.py +53 -0
- bda_practicals-0.1.0/bda_package/__main__.py +105 -0
- bda_practicals-0.1.0/bda_package/downloader.py +107 -0
- bda_practicals-0.1.0/bda_package/practical_3.py +86 -0
- bda_practicals-0.1.0/bda_package/practical_5.py +162 -0
- bda_practicals-0.1.0/bda_package/practical_6.py +95 -0
- bda_practicals-0.1.0/bda_package/practical_7.py +149 -0
- bda_practicals-0.1.0/bda_practicals.egg-info/PKG-INFO +71 -0
- bda_practicals-0.1.0/bda_practicals.egg-info/SOURCES.txt +19 -0
- bda_practicals-0.1.0/bda_practicals.egg-info/dependency_links.txt +1 -0
- bda_practicals-0.1.0/bda_practicals.egg-info/entry_points.txt +8 -0
- bda_practicals-0.1.0/bda_practicals.egg-info/top_level.txt +2 -0
- bda_practicals-0.1.0/pyproject.toml +3 -0
- bda_practicals-0.1.0/setup.cfg +4 -0
- bda_practicals-0.1.0/setup.py +38 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: bda-practicals
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: A collection of Big Data Analytics (BDA) practicals with instant one-word download commands (bda-3, bda-5, bda-6, bda-7).
|
|
5
|
+
Home-page: https://github.com/yourusername/bda-practicals
|
|
6
|
+
Author: Your Name
|
|
7
|
+
Author-email: your.email@example.com
|
|
8
|
+
Classifier: Programming Language :: Python :: 3
|
|
9
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
10
|
+
Classifier: Operating System :: OS Independent
|
|
11
|
+
Requires-Python: >=3.8
|
|
12
|
+
Description-Content-Type: text/markdown
|
|
13
|
+
License-File: LICENSE
|
|
14
|
+
Dynamic: author
|
|
15
|
+
Dynamic: author-email
|
|
16
|
+
Dynamic: classifier
|
|
17
|
+
Dynamic: description
|
|
18
|
+
Dynamic: description-content-type
|
|
19
|
+
Dynamic: home-page
|
|
20
|
+
Dynamic: license-file
|
|
21
|
+
Dynamic: requires-python
|
|
22
|
+
Dynamic: summary
|
|
23
|
+
|
|
24
|
+
# Big Data Analytics Practicals (`bda-practicals`)
|
|
25
|
+
|
|
26
|
+
A complete collection of Big Data Analytics (BDA) practical implementations with **instant one-word download commands** (`bda-3`, `bda-5`, `bda-6`, `bda-7`).
|
|
27
|
+
|
|
28
|
+
---
|
|
29
|
+
|
|
30
|
+
## ⚡ Instant One-Word Commands
|
|
31
|
+
|
|
32
|
+
Once installed via pip, just type the practical number you want:
|
|
33
|
+
|
|
34
|
+
| Command | Action | Output File in Downloads |
|
|
35
|
+
|---|---|---|
|
|
36
|
+
| **`bda-3`** | Downloads **Practical 3** (MapReduce Word Count Simulation) | `practical_3.py` |
|
|
37
|
+
| **`bda-5`** | Downloads **Practical 5** (DGIM Algorithm for Counting 1s) | `practical_5.py` |
|
|
38
|
+
| **`bda-6`** | Downloads **Practical 6** (Flajolet-Martin Algorithm for Distinct Count) | `practical_6.py` |
|
|
39
|
+
| **`bda-7`** | Downloads **Practical 7** (Bloom Filter Implementation) | `practical_7.py` |
|
|
40
|
+
|
|
41
|
+
> Running any command like `bda-5` immediately puts the clean `.py` file into your **Downloads** folder and **pops open Windows Explorer** so you can view, edit, and run the code!
|
|
42
|
+
|
|
43
|
+
### Download All Practicals at Once:
|
|
44
|
+
```bash
|
|
45
|
+
bda all
|
|
46
|
+
# OR
|
|
47
|
+
bda-all
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
---
|
|
51
|
+
|
|
52
|
+
## 🚀 How to Run on Any Computer
|
|
53
|
+
|
|
54
|
+
1. Open Terminal or Command Prompt:
|
|
55
|
+
```bash
|
|
56
|
+
pip install bda-practicals
|
|
57
|
+
```
|
|
58
|
+
2. Download any practical:
|
|
59
|
+
```bash
|
|
60
|
+
bda-5
|
|
61
|
+
# (Or bda-3, bda-6, bda-7)
|
|
62
|
+
```
|
|
63
|
+
3. Open the folder and run:
|
|
64
|
+
```bash
|
|
65
|
+
python practical_5.py
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
---
|
|
69
|
+
|
|
70
|
+
## License
|
|
71
|
+
MIT License
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# Big Data Analytics Practicals (`bda-practicals`)
|
|
2
|
+
|
|
3
|
+
A complete collection of Big Data Analytics (BDA) practical implementations with **instant one-word download commands** (`bda-3`, `bda-5`, `bda-6`, `bda-7`).
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## ⚡ Instant One-Word Commands
|
|
8
|
+
|
|
9
|
+
Once installed via pip, just type the practical number you want:
|
|
10
|
+
|
|
11
|
+
| Command | Action | Output File in Downloads |
|
|
12
|
+
|---|---|---|
|
|
13
|
+
| **`bda-3`** | Downloads **Practical 3** (MapReduce Word Count Simulation) | `practical_3.py` |
|
|
14
|
+
| **`bda-5`** | Downloads **Practical 5** (DGIM Algorithm for Counting 1s) | `practical_5.py` |
|
|
15
|
+
| **`bda-6`** | Downloads **Practical 6** (Flajolet-Martin Algorithm for Distinct Count) | `practical_6.py` |
|
|
16
|
+
| **`bda-7`** | Downloads **Practical 7** (Bloom Filter Implementation) | `practical_7.py` |
|
|
17
|
+
|
|
18
|
+
> Running any command like `bda-5` immediately puts the clean `.py` file into your **Downloads** folder and **pops open Windows Explorer** so you can view, edit, and run the code!
|
|
19
|
+
|
|
20
|
+
### Download All Practicals at Once:
|
|
21
|
+
```bash
|
|
22
|
+
bda all
|
|
23
|
+
# OR
|
|
24
|
+
bda-all
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
---
|
|
28
|
+
|
|
29
|
+
## 🚀 How to Run on Any Computer
|
|
30
|
+
|
|
31
|
+
1. Open Terminal or Command Prompt:
|
|
32
|
+
```bash
|
|
33
|
+
pip install bda-practicals
|
|
34
|
+
```
|
|
35
|
+
2. Download any practical:
|
|
36
|
+
```bash
|
|
37
|
+
bda-5
|
|
38
|
+
# (Or bda-3, bda-6, bda-7)
|
|
39
|
+
```
|
|
40
|
+
3. Open the folder and run:
|
|
41
|
+
```bash
|
|
42
|
+
python practical_5.py
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
---
|
|
46
|
+
|
|
47
|
+
## License
|
|
48
|
+
MIT License
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
"""
|
|
2
|
+
bda_package
|
|
3
|
+
===========
|
|
4
|
+
Big Data Analytics (BDA) practical implementations:
|
|
5
|
+
- Practical 3: MapReduce Word Count Simulation
|
|
6
|
+
- Practical 5: DGIM Algorithm (Counting 1s in a Sliding Window)
|
|
7
|
+
- Practical 6: Flajolet-Martin Algorithm (Distinct Elements Counting)
|
|
8
|
+
- Practical 7: Bloom Filter Implementation
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
from . import practical_3
|
|
12
|
+
from . import practical_5
|
|
13
|
+
from . import practical_6
|
|
14
|
+
from . import practical_7
|
|
15
|
+
from .downloader import download
|
|
16
|
+
|
|
17
|
+
export = download
|
|
18
|
+
|
|
19
|
+
__version__ = "0.1.0"
|
|
20
|
+
__all__ = [
|
|
21
|
+
"practical_3",
|
|
22
|
+
"practical_5",
|
|
23
|
+
"practical_6",
|
|
24
|
+
"practical_7",
|
|
25
|
+
"run_practical",
|
|
26
|
+
"run_all",
|
|
27
|
+
"download",
|
|
28
|
+
"export",
|
|
29
|
+
]
|
|
30
|
+
|
|
31
|
+
PRACTICALS = {
|
|
32
|
+
3: practical_3,
|
|
33
|
+
5: practical_5,
|
|
34
|
+
6: practical_6,
|
|
35
|
+
7: practical_7,
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def run_practical(number: int, **kwargs):
|
|
40
|
+
"""Run a specific BDA practical by number."""
|
|
41
|
+
if number not in PRACTICALS:
|
|
42
|
+
available = ", ".join(map(str, sorted(PRACTICALS.keys())))
|
|
43
|
+
raise ValueError(f"Practical {number} not found. Available: {available}")
|
|
44
|
+
return PRACTICALS[number].run(**kwargs)
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def run_all():
|
|
48
|
+
"""Run all BDA practicals sequentially."""
|
|
49
|
+
results = {}
|
|
50
|
+
for num, mod in sorted(PRACTICALS.items()):
|
|
51
|
+
print(f"\n{'='*25} RUNNING BDA PRACTICAL {num} {'='*25}")
|
|
52
|
+
results[num] = mod.run()
|
|
53
|
+
return results
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import sys
|
|
2
|
+
from . import run_practical, run_all, PRACTICALS
|
|
3
|
+
from .downloader import download
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def make_cli_for(num: int):
|
|
7
|
+
"""Factory to handle direct practical commands like bda-3, bda-5, etc."""
|
|
8
|
+
def handler():
|
|
9
|
+
if len(sys.argv) > 1:
|
|
10
|
+
arg = sys.argv[1].strip().lower()
|
|
11
|
+
if arg in ('--run', 'run'):
|
|
12
|
+
run_practical(num)
|
|
13
|
+
return
|
|
14
|
+
if arg in ('-h', '--help', 'help'):
|
|
15
|
+
print(f"Usage for bda-{num}:")
|
|
16
|
+
print(f" bda-{num} -> Download Practical {num} to Downloads")
|
|
17
|
+
print(f" bda-{num} run -> Run Practical {num} directly in terminal")
|
|
18
|
+
return
|
|
19
|
+
# Default behavior: download practical into Downloads and open folder!
|
|
20
|
+
download(num)
|
|
21
|
+
return handler
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
cli_p3 = make_cli_for(3)
|
|
25
|
+
cli_p5 = make_cli_for(5)
|
|
26
|
+
cli_p6 = make_cli_for(6)
|
|
27
|
+
cli_p7 = make_cli_for(7)
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def print_help():
|
|
31
|
+
print("""
|
|
32
|
+
Big Data Analytics (BDA) Practicals CLI
|
|
33
|
+
=======================================
|
|
34
|
+
Quick One-Word Download Commands:
|
|
35
|
+
bda-3 -> Downloads Practical 3 (MapReduce Word Count) to Downloads
|
|
36
|
+
bda-5 -> Downloads Practical 5 (DGIM Algorithm) to Downloads
|
|
37
|
+
bda-6 -> Downloads Practical 6 (Flajolet-Martin Algorithm) to Downloads
|
|
38
|
+
bda-7 -> Downloads Practical 7 (Bloom Filter) to Downloads
|
|
39
|
+
|
|
40
|
+
Download ALL BDA Practicals:
|
|
41
|
+
bda all -> Downloads all 4 practicals into Downloads/BDA_Practicals
|
|
42
|
+
bda-all -> Downloads all 4 practicals into Downloads/BDA_Practicals
|
|
43
|
+
|
|
44
|
+
Run in terminal:
|
|
45
|
+
bda-3 run -> Runs Practical 3 in terminal
|
|
46
|
+
bda-5 run -> Runs Practical 5 in terminal
|
|
47
|
+
bda run 6 -> Runs Practical 6 in terminal
|
|
48
|
+
""")
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def main():
|
|
52
|
+
if len(sys.argv) < 2:
|
|
53
|
+
# Default action when just running "bda":
|
|
54
|
+
# Download Practical 5 into Downloads folder and open it!
|
|
55
|
+
print("No practical specified. Downloading BDA Practical 5 (DGIM Algorithm)...")
|
|
56
|
+
download(5)
|
|
57
|
+
return
|
|
58
|
+
|
|
59
|
+
command = sys.argv[1].strip().lower()
|
|
60
|
+
|
|
61
|
+
if command in ("-h", "--help", "help"):
|
|
62
|
+
print_help()
|
|
63
|
+
return
|
|
64
|
+
|
|
65
|
+
# Check for download / get / export commands
|
|
66
|
+
if command in ("download", "get", "export"):
|
|
67
|
+
target_num = sys.argv[2].strip().lower() if len(sys.argv) > 2 else "5"
|
|
68
|
+
download(target_num)
|
|
69
|
+
return
|
|
70
|
+
|
|
71
|
+
# Check for run command
|
|
72
|
+
if command == "run":
|
|
73
|
+
target = sys.argv[2].strip().lower() if len(sys.argv) > 2 else "5"
|
|
74
|
+
if target == "all":
|
|
75
|
+
run_all()
|
|
76
|
+
else:
|
|
77
|
+
try:
|
|
78
|
+
num = int(target)
|
|
79
|
+
run_practical(num)
|
|
80
|
+
except ValueError:
|
|
81
|
+
print(f"Error: Invalid practical number '{target}'.")
|
|
82
|
+
return
|
|
83
|
+
|
|
84
|
+
if command in ("all", "bda-all"):
|
|
85
|
+
download("all")
|
|
86
|
+
return
|
|
87
|
+
|
|
88
|
+
# Direct number (e.g. "bda 5")
|
|
89
|
+
try:
|
|
90
|
+
num = int(command)
|
|
91
|
+
if num in PRACTICALS:
|
|
92
|
+
download(num)
|
|
93
|
+
else:
|
|
94
|
+
available = ", ".join(map(str, sorted(PRACTICALS.keys())))
|
|
95
|
+
print(f"Error: Practical number must be one of: {available}. Received: {num}")
|
|
96
|
+
print_help()
|
|
97
|
+
sys.exit(1)
|
|
98
|
+
except ValueError:
|
|
99
|
+
print(f"Error: Unrecognized option '{command}'.")
|
|
100
|
+
print_help()
|
|
101
|
+
sys.exit(1)
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
if __name__ == '__main__':
|
|
105
|
+
main()
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import sys
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
|
|
5
|
+
TEMPLATES = {}
|
|
6
|
+
|
|
7
|
+
# Read templates directly from the package files so they always stay 100% in sync!
|
|
8
|
+
def _load_templates():
|
|
9
|
+
pkg_dir = Path(__file__).parent
|
|
10
|
+
mapping = {
|
|
11
|
+
3: pkg_dir / "practical_3.py",
|
|
12
|
+
5: pkg_dir / "practical_5.py",
|
|
13
|
+
6: pkg_dir / "practical_6.py",
|
|
14
|
+
7: pkg_dir / "practical_7.py",
|
|
15
|
+
}
|
|
16
|
+
for num, filepath in mapping.items():
|
|
17
|
+
if filepath.exists():
|
|
18
|
+
with open(filepath, "r", encoding="utf-8") as f:
|
|
19
|
+
TEMPLATES[num] = f.read()
|
|
20
|
+
|
|
21
|
+
_load_templates()
|
|
22
|
+
|
|
23
|
+
PRACTICAL_NAMES = {
|
|
24
|
+
3: "MapReduce Word Count Simulation",
|
|
25
|
+
5: "DGIM Algorithm (Counting 1s in Sliding Window)",
|
|
26
|
+
6: "Flajolet-Martin Algorithm (Distinct Elements Counting)",
|
|
27
|
+
7: "Bloom Filter Implementation",
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def get_default_download_dir(practical_num=None):
|
|
32
|
+
"""Returns the Downloads directory on Windows/Mac/Linux."""
|
|
33
|
+
downloads_path = Path.home() / "Downloads"
|
|
34
|
+
if not downloads_path.exists():
|
|
35
|
+
downloads_path = Path.cwd()
|
|
36
|
+
|
|
37
|
+
if practical_num is None or str(practical_num).lower() == 'all':
|
|
38
|
+
target_dir = downloads_path / "BDA_Practicals"
|
|
39
|
+
else:
|
|
40
|
+
target_dir = downloads_path / f"BDA_Practical_{practical_num}"
|
|
41
|
+
|
|
42
|
+
target_dir.mkdir(parents=True, exist_ok=True)
|
|
43
|
+
return target_dir
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def download(practical_num=3, target_dir=None, open_folder=True):
|
|
47
|
+
"""
|
|
48
|
+
Downloads/exports the specified BDA practical script
|
|
49
|
+
directly to the user's Downloads folder or a specified target directory.
|
|
50
|
+
"""
|
|
51
|
+
if not TEMPLATES:
|
|
52
|
+
_load_templates()
|
|
53
|
+
|
|
54
|
+
if isinstance(practical_num, str) and practical_num.lower() == 'all':
|
|
55
|
+
numbers = sorted(list(TEMPLATES.keys()))
|
|
56
|
+
if target_dir is None:
|
|
57
|
+
target_path = get_default_download_dir('all')
|
|
58
|
+
else:
|
|
59
|
+
target_path = Path(target_dir)
|
|
60
|
+
target_path.mkdir(parents=True, exist_ok=True)
|
|
61
|
+
else:
|
|
62
|
+
try:
|
|
63
|
+
num = int(practical_num)
|
|
64
|
+
if num not in TEMPLATES:
|
|
65
|
+
available = ", ".join(map(str, sorted(TEMPLATES.keys())))
|
|
66
|
+
raise ValueError(f"Practical {num} not found. Available practicals: {available}")
|
|
67
|
+
numbers = [num]
|
|
68
|
+
if target_dir is None:
|
|
69
|
+
target_path = get_default_download_dir(num)
|
|
70
|
+
else:
|
|
71
|
+
target_path = Path(target_dir)
|
|
72
|
+
target_path.mkdir(parents=True, exist_ok=True)
|
|
73
|
+
except ValueError as e:
|
|
74
|
+
raise ValueError(f"Invalid practical number: '{practical_num}'. {e}")
|
|
75
|
+
|
|
76
|
+
created_files = []
|
|
77
|
+
|
|
78
|
+
for num in numbers:
|
|
79
|
+
py_filename = f"practical_{num}.py"
|
|
80
|
+
py_filepath = target_path / py_filename
|
|
81
|
+
with open(py_filepath, 'w', encoding='utf-8') as f:
|
|
82
|
+
f.write(TEMPLATES[num])
|
|
83
|
+
created_files.append((py_filename, PRACTICAL_NAMES.get(num, "BDA Practical")))
|
|
84
|
+
|
|
85
|
+
print("\n" + "=" * 65)
|
|
86
|
+
print("SUCCESS! Downloaded BDA Practical files:")
|
|
87
|
+
print(f"Folder: {target_path}")
|
|
88
|
+
for fname, desc in created_files:
|
|
89
|
+
print(f" - {fname} ({desc})")
|
|
90
|
+
print("=" * 65)
|
|
91
|
+
print("To run:")
|
|
92
|
+
if len(numbers) == 1:
|
|
93
|
+
print(f" cd \"{target_path}\"")
|
|
94
|
+
print(f" python practical_{numbers[0]}.py")
|
|
95
|
+
else:
|
|
96
|
+
print(f" cd \"{target_path}\"")
|
|
97
|
+
print(" python practical_3.py (or practical_5.py, practical_6.py, practical_7.py)")
|
|
98
|
+
print("=" * 65 + "\n")
|
|
99
|
+
|
|
100
|
+
# Automatically open folder in Windows Explorer / OS file manager
|
|
101
|
+
if open_folder and sys.platform == 'win32':
|
|
102
|
+
try:
|
|
103
|
+
os.startfile(target_path)
|
|
104
|
+
except Exception:
|
|
105
|
+
pass
|
|
106
|
+
|
|
107
|
+
return str(target_path)
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
from collections import defaultdict
|
|
2
|
+
|
|
3
|
+
# ==========================================
|
|
4
|
+
# 1. MAPPER FUNCTION
|
|
5
|
+
# ==========================================
|
|
6
|
+
def mapper(document_id: int, text: str):
|
|
7
|
+
"""
|
|
8
|
+
Takes a document, cleans/tokenizes it, and emits
|
|
9
|
+
key-value pairs of the format: (word, 1).
|
|
10
|
+
"""
|
|
11
|
+
mapped_pairs = []
|
|
12
|
+
# Convert text to lowercase and split into words
|
|
13
|
+
words = text.lower().split()
|
|
14
|
+
|
|
15
|
+
for word in words:
|
|
16
|
+
# Strip common punctuation marks
|
|
17
|
+
cleaned_word = word.strip(".,!?;:\"'")
|
|
18
|
+
if cleaned_word:
|
|
19
|
+
mapped_pairs.append((cleaned_word, 1))
|
|
20
|
+
|
|
21
|
+
return mapped_pairs
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
# ==========================================
|
|
25
|
+
# 2. SHUFFLE & SORT PHASE (Framework step)
|
|
26
|
+
# ==========================================
|
|
27
|
+
def shuffle_and_sort(mapped_results):
|
|
28
|
+
"""
|
|
29
|
+
Groups all values associated with the same key (word)
|
|
30
|
+
into a single list: {word: [1, 1, 1, ...]}
|
|
31
|
+
"""
|
|
32
|
+
grouped_data = defaultdict(list)
|
|
33
|
+
for word, count in mapped_results:
|
|
34
|
+
grouped_data[word].append(count)
|
|
35
|
+
return grouped_data
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
# ==========================================
|
|
39
|
+
# 3. REDUCER FUNCTION
|
|
40
|
+
# ==========================================
|
|
41
|
+
def reducer(word, counts):
|
|
42
|
+
"""
|
|
43
|
+
Takes a word and its list of counts, aggregates them,
|
|
44
|
+
and outputs the final total frequency for that word.
|
|
45
|
+
"""
|
|
46
|
+
return (word, sum(counts))
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
# ==========================================
|
|
50
|
+
# DRIVER PROGRAM / SIMULATION
|
|
51
|
+
# ==========================================
|
|
52
|
+
def run():
|
|
53
|
+
# Sample input dataset (representing multiple documents/lines in a stream)
|
|
54
|
+
documents = {
|
|
55
|
+
1: "Big Data analysis using MapReduce framework.",
|
|
56
|
+
2: "MapReduce is a programming model for data processing.",
|
|
57
|
+
3: "Big data and map reduce make data processing fast and scalable."
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
print("=== Step 1: Mapping Phase ===")
|
|
61
|
+
all_mapped = []
|
|
62
|
+
for doc_id, text in documents.items():
|
|
63
|
+
pairs = mapper(doc_id, text)
|
|
64
|
+
print(f"Doc {doc_id} Mapped -> {pairs}")
|
|
65
|
+
all_mapped.extend(pairs)
|
|
66
|
+
|
|
67
|
+
print("\n=== Step 2: Shuffle and Sort Phase ===")
|
|
68
|
+
grouped_data = shuffle_and_sort(all_mapped)
|
|
69
|
+
for word, counts in grouped_data.items():
|
|
70
|
+
print(f"Key: '{word}' => Values: {counts}")
|
|
71
|
+
|
|
72
|
+
print("\n=== Step 3: Reducing Phase ===")
|
|
73
|
+
final_word_counts = {}
|
|
74
|
+
for word, counts in grouped_data.items():
|
|
75
|
+
reduced_word, total_count = reducer(word, counts)
|
|
76
|
+
final_word_counts[reduced_word] = total_count
|
|
77
|
+
|
|
78
|
+
print("\n=== Final Output (Word Counts) ===")
|
|
79
|
+
for word, count in sorted(final_word_counts.items()):
|
|
80
|
+
print(f" {word}: {count}")
|
|
81
|
+
|
|
82
|
+
return final_word_counts
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
if __name__ == "__main__":
|
|
86
|
+
run()
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
class DGIMStream:
|
|
2
|
+
def __init__(self, window_size: int):
|
|
3
|
+
self.window_size = window_size
|
|
4
|
+
self.current_time = 0
|
|
5
|
+
self.buckets = []
|
|
6
|
+
|
|
7
|
+
def _resolve_buckets(self, verbose: bool = False):
|
|
8
|
+
i = 0
|
|
9
|
+
while i < len(self.buckets):
|
|
10
|
+
current_size = self.buckets[i]['size']
|
|
11
|
+
matching_indices = [idx for idx, b in enumerate(self.buckets) if b['size'] == current_size]
|
|
12
|
+
if len(matching_indices) > 2:
|
|
13
|
+
if verbose:
|
|
14
|
+
print(f" [MERGE TRIGGER] Found {len(matching_indices)} buckets of size {current_size}. Merging the two oldest...")
|
|
15
|
+
|
|
16
|
+
oldest_idx_2 = matching_indices[-1]
|
|
17
|
+
oldest_idx_1 = matching_indices[-2]
|
|
18
|
+
|
|
19
|
+
merged_size = current_size * 2
|
|
20
|
+
merged_timestamp = self.buckets[oldest_idx_1]['timestamp']
|
|
21
|
+
|
|
22
|
+
if verbose:
|
|
23
|
+
print(f" - Merging bucket (size {current_size}, ts {self.buckets[oldest_idx_2]['timestamp']}) "
|
|
24
|
+
f"and bucket (size {current_size}, ts {self.buckets[oldest_idx_1]['timestamp']})")
|
|
25
|
+
print(f" - Created new bucket: size {merged_size}, timestamp {merged_timestamp}")
|
|
26
|
+
|
|
27
|
+
del self.buckets[oldest_idx_2]
|
|
28
|
+
del self.buckets[oldest_idx_1]
|
|
29
|
+
|
|
30
|
+
inserted = False
|
|
31
|
+
for idx, b in enumerate(self.buckets):
|
|
32
|
+
if b['timestamp'] < merged_timestamp:
|
|
33
|
+
self.buckets.insert(idx, {'size': merged_size, 'timestamp': merged_timestamp})
|
|
34
|
+
inserted = True
|
|
35
|
+
break
|
|
36
|
+
if not inserted:
|
|
37
|
+
self.buckets.append({'size': merged_size, 'timestamp': merged_timestamp})
|
|
38
|
+
|
|
39
|
+
# Restart check from the beginning to handle cascading merges
|
|
40
|
+
i = 0
|
|
41
|
+
else:
|
|
42
|
+
i += 1
|
|
43
|
+
|
|
44
|
+
def add_bit(self, bit: int, verbose: bool = True):
|
|
45
|
+
"""Processes an incoming bit (0 or 1) into the stream."""
|
|
46
|
+
if bit not in (0, 1):
|
|
47
|
+
print("Error: Bit must be 0 or 1.")
|
|
48
|
+
return
|
|
49
|
+
|
|
50
|
+
self.current_time += 1
|
|
51
|
+
if verbose:
|
|
52
|
+
print(f"\n[STREAM EVENT] Time t={self.current_time} | Received Bit: {bit}")
|
|
53
|
+
|
|
54
|
+
# Expire old buckets outside the current sliding window window_size
|
|
55
|
+
cutoff_time = self.current_time - self.window_size
|
|
56
|
+
expired_buckets = [b for b in self.buckets if b['timestamp'] <= cutoff_time]
|
|
57
|
+
if expired_buckets and verbose:
|
|
58
|
+
print(f" [EXPIRY] Removing buckets with timestamp <= {cutoff_time}")
|
|
59
|
+
self.buckets = [b for b in self.buckets if b['timestamp'] > cutoff_time]
|
|
60
|
+
|
|
61
|
+
# If bit is 1, create a new bucket of size 1 at the current timestamp
|
|
62
|
+
if bit == 1:
|
|
63
|
+
if verbose:
|
|
64
|
+
print(f" [INSERT] Bit is 1. Adding new bucket: size=1, timestamp={self.current_time}")
|
|
65
|
+
self.buckets.insert(0, {'size': 1, 'timestamp': self.current_time})
|
|
66
|
+
self._resolve_buckets(verbose=verbose)
|
|
67
|
+
else:
|
|
68
|
+
if verbose:
|
|
69
|
+
print(f" [INFO] Bit is 0. No new bucket created.")
|
|
70
|
+
|
|
71
|
+
if verbose:
|
|
72
|
+
self.print_buckets()
|
|
73
|
+
|
|
74
|
+
def query(self, k: int) -> int:
|
|
75
|
+
"""Estimates the number of 1s in the last k elements of the stream."""
|
|
76
|
+
if k <= 0:
|
|
77
|
+
return 0
|
|
78
|
+
|
|
79
|
+
start_time = self.current_time - k + 1
|
|
80
|
+
estimated_ones = 0
|
|
81
|
+
|
|
82
|
+
print(f"\n[QUERY EVALUATION] Estimating 1s in last {k} elements (Window: t={start_time} to t={self.current_time})")
|
|
83
|
+
|
|
84
|
+
last_bucket = None
|
|
85
|
+
for b in self.buckets:
|
|
86
|
+
if b['timestamp'] >= start_time:
|
|
87
|
+
estimated_ones += b['size']
|
|
88
|
+
print(f" - Fully inside window: Bucket(size={b['size']}, ts={b['timestamp']}) -> Added {b['size']}")
|
|
89
|
+
else:
|
|
90
|
+
# This bucket is partially outside the window
|
|
91
|
+
last_bucket = b
|
|
92
|
+
print(f" - Partially outside window: Bucket(size={b['size']}, ts={b['timestamp']}) -> Will add half weight")
|
|
93
|
+
break
|
|
94
|
+
|
|
95
|
+
# DGIM Heuristic: Add half the size of the oldest bucket that overlaps the boundary
|
|
96
|
+
if last_bucket:
|
|
97
|
+
half_size = last_bucket['size'] // 2
|
|
98
|
+
estimated_ones += half_size
|
|
99
|
+
print(f" -> Added half of boundary bucket size ({last_bucket['size']} / 2 = {half_size})")
|
|
100
|
+
|
|
101
|
+
print(f"Final Estimated Count of 1s in last {k} elements: **{estimated_ones}**\n")
|
|
102
|
+
return estimated_ones
|
|
103
|
+
|
|
104
|
+
def print_buckets(self):
|
|
105
|
+
"""Displays the current structural state of DGIM buckets."""
|
|
106
|
+
print(f"[CURRENT BUCKETS STATE (Newest -> Oldest)]")
|
|
107
|
+
if not self.buckets:
|
|
108
|
+
print(" (No active buckets)")
|
|
109
|
+
else:
|
|
110
|
+
for idx, b in enumerate(self.buckets):
|
|
111
|
+
print(f" [{idx}] Size: {b['size']} | Timestamp: {b['timestamp']}")
|
|
112
|
+
print("")
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
def main():
|
|
116
|
+
try:
|
|
117
|
+
window_size = int(input("Enter sliding window size N "))
|
|
118
|
+
except ValueError:
|
|
119
|
+
print("Invalid input. Using default window size N=10.")
|
|
120
|
+
window_size = 10
|
|
121
|
+
|
|
122
|
+
dgim = DGIMStream(window_size=window_size)
|
|
123
|
+
|
|
124
|
+
while True:
|
|
125
|
+
print("Menu:")
|
|
126
|
+
print(" 1. Add a bit to stream (0 or 1)")
|
|
127
|
+
print(" 2. Query count of 1s in last k elements")
|
|
128
|
+
print(" 3. View current buckets state")
|
|
129
|
+
print(" 4. Exit")
|
|
130
|
+
|
|
131
|
+
choice = input("\nChoose an option (1-4): ").strip()
|
|
132
|
+
|
|
133
|
+
if choice == '1':
|
|
134
|
+
try:
|
|
135
|
+
bit = int(input("Enter bit (0 or 1): ").strip())
|
|
136
|
+
if bit in (0, 1):
|
|
137
|
+
dgim.add_bit(bit, verbose=True)
|
|
138
|
+
else:
|
|
139
|
+
print("Please enter strictly 0 or 1.")
|
|
140
|
+
except ValueError:
|
|
141
|
+
print("Invalid input. Enter an integer 0 or 1.")
|
|
142
|
+
elif choice == '2':
|
|
143
|
+
try:
|
|
144
|
+
k = int(input(f"Enter query length k (1 to {dgim.window_size}): ").strip())
|
|
145
|
+
dgim.query(k)
|
|
146
|
+
except ValueError:
|
|
147
|
+
print("Invalid input. Enter a valid integer.")
|
|
148
|
+
elif choice == '3':
|
|
149
|
+
dgim.print_buckets()
|
|
150
|
+
elif choice == '4':
|
|
151
|
+
print("Exiting DGIM Stream CLI. Goodbye!")
|
|
152
|
+
break
|
|
153
|
+
else:
|
|
154
|
+
print("Invalid option. Please choose between 1 and 4.")
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
def run():
|
|
158
|
+
main()
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
if __name__ == "__main__":
|
|
162
|
+
main()
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import hashlib
|
|
2
|
+
|
|
3
|
+
class FlajoletMartin:
|
|
4
|
+
def __init__(self, num_hashes: int = 4):
|
|
5
|
+
self.num_hashes = num_hashes
|
|
6
|
+
self.max_zeros = [0] * num_hashes
|
|
7
|
+
self.stream_count = 0
|
|
8
|
+
|
|
9
|
+
def _hash(self, item: str, seed: int, verbose: bool = False) -> int:
|
|
10
|
+
salted = (str(seed) + item).encode('utf-8')
|
|
11
|
+
digest_hex = hashlib.md5(salted).hexdigest()
|
|
12
|
+
digest_int = int(digest_hex, 16)
|
|
13
|
+
if verbose:
|
|
14
|
+
print(f" [Hash Function #{seed + 1}]")
|
|
15
|
+
print(f" - Salted String : '{salted.decode()}'")
|
|
16
|
+
print(f" - MD5 Hex Digest: {digest_hex}")
|
|
17
|
+
print(f" - Integer Value : {digest_int}")
|
|
18
|
+
return digest_int
|
|
19
|
+
|
|
20
|
+
def _trailing_zeros(self, n: int) -> int:
|
|
21
|
+
if n == 0:
|
|
22
|
+
return 0
|
|
23
|
+
return (n & -n).bit_length() - 1
|
|
24
|
+
|
|
25
|
+
def add_item(self, item: str, verbose: bool = True):
|
|
26
|
+
self.stream_count += 1
|
|
27
|
+
if verbose:
|
|
28
|
+
print(f"\n[STREAM ITEM #{self.stream_count}] Processing item: '{item}'")
|
|
29
|
+
for i in range(self.num_hashes):
|
|
30
|
+
h_val = self._hash(item, seed=i, verbose=verbose)
|
|
31
|
+
tz = self._trailing_zeros(h_val)
|
|
32
|
+
prev_max = self.max_zeros[i]
|
|
33
|
+
updated = False
|
|
34
|
+
if tz > prev_max:
|
|
35
|
+
self.max_zeros[i] = tz
|
|
36
|
+
updated = True
|
|
37
|
+
if verbose:
|
|
38
|
+
print(f" - Trailing Zeros (R): {tz}")
|
|
39
|
+
print(f" - Max R[{i+1}] Tracked: {prev_max} -> Updated Max: {self.max_zeros[i]} {'(NEW MAX!)' if updated else ''}")
|
|
40
|
+
|
|
41
|
+
if verbose:
|
|
42
|
+
print(f"Current Max Zeros Array across all hash functions: {self.max_zeros}\n")
|
|
43
|
+
|
|
44
|
+
def get_estimate(self) -> float:
|
|
45
|
+
phi = 0.77351
|
|
46
|
+
avg_two_to_r = sum(2 ** r for r in self.max_zeros) / self.num_hashes
|
|
47
|
+
estimate = avg_two_to_r / phi
|
|
48
|
+
return round(estimate, 2)
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def main():
|
|
52
|
+
try:
|
|
53
|
+
num_hashes = int(input("Enter number of hash functions: "))
|
|
54
|
+
except ValueError:
|
|
55
|
+
print("Invalid input. Using default: 4 hash functions.")
|
|
56
|
+
num_hashes = 4
|
|
57
|
+
|
|
58
|
+
fm = FlajoletMartin(num_hashes=num_hashes)
|
|
59
|
+
|
|
60
|
+
while True:
|
|
61
|
+
print("Menu:")
|
|
62
|
+
print(" 1. Add an item to stream")
|
|
63
|
+
print(" 2. View current distinct element estimation")
|
|
64
|
+
print(" 3. View current Max Zeros array state (R)")
|
|
65
|
+
print(" 4. Exit")
|
|
66
|
+
choice = input("\nChoose an option (1-4): ").strip()
|
|
67
|
+
if choice == '1':
|
|
68
|
+
item = input("Enter item/element: ").strip()
|
|
69
|
+
if item:
|
|
70
|
+
fm.add_item(item, verbose=True)
|
|
71
|
+
else:
|
|
72
|
+
print("Item cannot be empty.")
|
|
73
|
+
elif choice == '2':
|
|
74
|
+
estimate = fm.get_estimate()
|
|
75
|
+
print(f"\n[ESTIMATION REPORT]")
|
|
76
|
+
print(f" - Total items processed : {fm.stream_count}")
|
|
77
|
+
print(f" - Max Zeros Array (R) : {fm.max_zeros}")
|
|
78
|
+
print(f" - Estimated Distinct Count: **{estimate}**\n")
|
|
79
|
+
elif choice == '3':
|
|
80
|
+
print(f"\n[STATE INSPECTION]")
|
|
81
|
+
print(f" - Total items streamed : {fm.stream_count}")
|
|
82
|
+
print(f" - Max Zeros Array (R) : {fm.max_zeros}\n")
|
|
83
|
+
elif choice == '4':
|
|
84
|
+
print("Exiting FM Algorithm CLI. Goodbye!")
|
|
85
|
+
break
|
|
86
|
+
else:
|
|
87
|
+
print("Invalid option. Please choose between 1 and 4.")
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
def run():
|
|
91
|
+
main()
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
if __name__ == "__main__":
|
|
95
|
+
main()
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
import hashlib
|
|
2
|
+
|
|
3
|
+
class BloomFilter:
|
|
4
|
+
def __init__(self, size: int, num_hashes: int):
|
|
5
|
+
self.size = size
|
|
6
|
+
self.num_hashes = num_hashes
|
|
7
|
+
self.bit_array = [0] * size
|
|
8
|
+
|
|
9
|
+
def _hashes(self, item: str, verbose: bool = False):
|
|
10
|
+
"""Generates k different hash indices for a given item, with optional detailed logging."""
|
|
11
|
+
indices = []
|
|
12
|
+
if verbose:
|
|
13
|
+
print(f"[DEBUG] Processing item: '{item}'")
|
|
14
|
+
print(f"[DEBUG] Target Bit Array Size: {self.size}, Hash Count: {self.num_hashes}")
|
|
15
|
+
|
|
16
|
+
for i in range(self.num_hashes):
|
|
17
|
+
# Create salted string and encode to bytes
|
|
18
|
+
salted_str = str(i) + item
|
|
19
|
+
salted_bytes = salted_str.encode('utf-8')
|
|
20
|
+
|
|
21
|
+
# Generate MD5 hash digest
|
|
22
|
+
digest_hex = hashlib.md5(salted_bytes).hexdigest()
|
|
23
|
+
|
|
24
|
+
# Convert hex digest to integer and map to array index
|
|
25
|
+
digest_int = int(digest_hex, 16)
|
|
26
|
+
index = digest_int % self.size
|
|
27
|
+
indices.append(index)
|
|
28
|
+
|
|
29
|
+
if verbose:
|
|
30
|
+
print(f" [Hash #{i + 1}]")
|
|
31
|
+
print(f" - Salted String : '{salted_str}'")
|
|
32
|
+
print(f" - Byte Encoding : {list(salted_bytes)}")
|
|
33
|
+
print(f" - MD5 Hex Digest: {digest_hex}")
|
|
34
|
+
print(f" - Integer Value : {digest_int}")
|
|
35
|
+
print(f" - Mapped Index : {digest_int} % {self.size} = **Index {index}**")
|
|
36
|
+
|
|
37
|
+
if verbose:
|
|
38
|
+
print(f"[DEBUG] Final Computed Indices: {indices}")
|
|
39
|
+
|
|
40
|
+
return indices
|
|
41
|
+
|
|
42
|
+
def add(self, item: str, verbose: bool = True):
|
|
43
|
+
"""Adds an item to the Bloom filter and displays bit changes."""
|
|
44
|
+
if verbose:
|
|
45
|
+
print(f"\n[ADD OPERATION] Adding '{item}'...")
|
|
46
|
+
|
|
47
|
+
indices = self._hashes(item, verbose=verbose)
|
|
48
|
+
|
|
49
|
+
changed_bits = []
|
|
50
|
+
for index in indices:
|
|
51
|
+
previous_state = self.bit_array[index]
|
|
52
|
+
self.bit_array[index] = 1
|
|
53
|
+
changed_bits.append((index, previous_state, self.bit_array[index]))
|
|
54
|
+
|
|
55
|
+
if verbose:
|
|
56
|
+
print(f"[BIT-FLIP SUMMARY]")
|
|
57
|
+
for idx, prev, curr in changed_bits:
|
|
58
|
+
status = "changed 0 -> 1" if prev == 0 else "already 1"
|
|
59
|
+
print(f" - Bit Index [{idx}]: {status}")
|
|
60
|
+
self.print_bit_array()
|
|
61
|
+
|
|
62
|
+
def check(self, item: str, verbose: bool = True) -> bool:
|
|
63
|
+
"""Checks if an item is in the Bloom filter with detailed inspection steps."""
|
|
64
|
+
if verbose:
|
|
65
|
+
print(f"\n[CHECK OPERATION] Checking if '{item}' exists...")
|
|
66
|
+
|
|
67
|
+
indices = self._hashes(item, verbose=verbose)
|
|
68
|
+
|
|
69
|
+
exists = True
|
|
70
|
+
if verbose:
|
|
71
|
+
print(f"[LOOKUP EVALUATION]")
|
|
72
|
+
|
|
73
|
+
for index in indices:
|
|
74
|
+
val = self.bit_array[index]
|
|
75
|
+
if verbose:
|
|
76
|
+
print(f" - Inspecting Index [{index}]: Found value **{val}**")
|
|
77
|
+
if val == 0:
|
|
78
|
+
exists = False
|
|
79
|
+
|
|
80
|
+
if verbose:
|
|
81
|
+
print(f" -> Conclusion: All indices checked. Final result = {exists}")
|
|
82
|
+
|
|
83
|
+
return exists
|
|
84
|
+
|
|
85
|
+
def print_bit_array(self):
|
|
86
|
+
print(f"\n[CURRENT BIT ARRAY STATE]")
|
|
87
|
+
if self.size <= 60:
|
|
88
|
+
indices_str = " ".join(f"{i:2}" for i in range(self.size))
|
|
89
|
+
separator = "-" * len(indices_str)
|
|
90
|
+
print(f" Indices: {indices_str}")
|
|
91
|
+
print(f" {separator}")
|
|
92
|
+
bits_str = " ".join(f"{b:2}" for b in self.bit_array)
|
|
93
|
+
print(f" Values : {bits_str}")
|
|
94
|
+
else:
|
|
95
|
+
non_zero_count = sum(self.bit_array)
|
|
96
|
+
print(f" Size: {self.size} bits | Active bits (1s): {non_zero_count} | Zero bits (0s): {self.size - non_zero_count}")
|
|
97
|
+
print(f" Raw Bit Array {self.bit_array[:50]}...")
|
|
98
|
+
print("")
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
def main():
|
|
102
|
+
try:
|
|
103
|
+
size = int(input("Enter bit array size: "))
|
|
104
|
+
num_hashes = int(input("Enter number of hash functions: "))
|
|
105
|
+
except ValueError:
|
|
106
|
+
print("Using default values: size=40, num_hashes=3")
|
|
107
|
+
size, num_hashes = 40, 3
|
|
108
|
+
|
|
109
|
+
bf = BloomFilter(size, num_hashes)
|
|
110
|
+
bf.print_bit_array()
|
|
111
|
+
|
|
112
|
+
while True:
|
|
113
|
+
print("Menu:")
|
|
114
|
+
print(" 1. Add an item")
|
|
115
|
+
print(" 2. Check an item")
|
|
116
|
+
print(" 3. View current bit array")
|
|
117
|
+
print(" 4. Exit")
|
|
118
|
+
choice = input("\nChoose an option (1-4): ").strip()
|
|
119
|
+
if choice == '1':
|
|
120
|
+
item = input("Enter string to add: ").strip()
|
|
121
|
+
if item:
|
|
122
|
+
bf.add(item, verbose=True)
|
|
123
|
+
else:
|
|
124
|
+
print("Item cannot be empty.")
|
|
125
|
+
elif choice == '2':
|
|
126
|
+
item = input("Enter string to check: ").strip()
|
|
127
|
+
if item:
|
|
128
|
+
found = bf.check(item, verbose=True)
|
|
129
|
+
if found:
|
|
130
|
+
print(f"RESULT: '{item}' **MIGHT BE PRESENT** in the set.")
|
|
131
|
+
else:
|
|
132
|
+
print(f"RESULT: '{item}' is **DEFINITELY NOT PRESENT** in the set.")
|
|
133
|
+
else:
|
|
134
|
+
print("Item cannot be empty.")
|
|
135
|
+
elif choice == '3':
|
|
136
|
+
bf.print_bit_array()
|
|
137
|
+
elif choice == '4':
|
|
138
|
+
print("Exiting Bloom Filter CLI. Goodbye!")
|
|
139
|
+
break
|
|
140
|
+
else:
|
|
141
|
+
print("Invalid option. Please choose between 1 and 4.")
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
def run():
|
|
145
|
+
main()
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
if __name__ == "__main__":
|
|
149
|
+
main()
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: bda-practicals
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: A collection of Big Data Analytics (BDA) practicals with instant one-word download commands (bda-3, bda-5, bda-6, bda-7).
|
|
5
|
+
Home-page: https://github.com/yourusername/bda-practicals
|
|
6
|
+
Author: Your Name
|
|
7
|
+
Author-email: your.email@example.com
|
|
8
|
+
Classifier: Programming Language :: Python :: 3
|
|
9
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
10
|
+
Classifier: Operating System :: OS Independent
|
|
11
|
+
Requires-Python: >=3.8
|
|
12
|
+
Description-Content-Type: text/markdown
|
|
13
|
+
License-File: LICENSE
|
|
14
|
+
Dynamic: author
|
|
15
|
+
Dynamic: author-email
|
|
16
|
+
Dynamic: classifier
|
|
17
|
+
Dynamic: description
|
|
18
|
+
Dynamic: description-content-type
|
|
19
|
+
Dynamic: home-page
|
|
20
|
+
Dynamic: license-file
|
|
21
|
+
Dynamic: requires-python
|
|
22
|
+
Dynamic: summary
|
|
23
|
+
|
|
24
|
+
# Big Data Analytics Practicals (`bda-practicals`)
|
|
25
|
+
|
|
26
|
+
A complete collection of Big Data Analytics (BDA) practical implementations with **instant one-word download commands** (`bda-3`, `bda-5`, `bda-6`, `bda-7`).
|
|
27
|
+
|
|
28
|
+
---
|
|
29
|
+
|
|
30
|
+
## ⚡ Instant One-Word Commands
|
|
31
|
+
|
|
32
|
+
Once installed via pip, just type the practical number you want:
|
|
33
|
+
|
|
34
|
+
| Command | Action | Output File in Downloads |
|
|
35
|
+
|---|---|---|
|
|
36
|
+
| **`bda-3`** | Downloads **Practical 3** (MapReduce Word Count Simulation) | `practical_3.py` |
|
|
37
|
+
| **`bda-5`** | Downloads **Practical 5** (DGIM Algorithm for Counting 1s) | `practical_5.py` |
|
|
38
|
+
| **`bda-6`** | Downloads **Practical 6** (Flajolet-Martin Algorithm for Distinct Count) | `practical_6.py` |
|
|
39
|
+
| **`bda-7`** | Downloads **Practical 7** (Bloom Filter Implementation) | `practical_7.py` |
|
|
40
|
+
|
|
41
|
+
> Running any command like `bda-5` immediately puts the clean `.py` file into your **Downloads** folder and **pops open Windows Explorer** so you can view, edit, and run the code!
|
|
42
|
+
|
|
43
|
+
### Download All Practicals at Once:
|
|
44
|
+
```bash
|
|
45
|
+
bda all
|
|
46
|
+
# OR
|
|
47
|
+
bda-all
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
---
|
|
51
|
+
|
|
52
|
+
## 🚀 How to Run on Any Computer
|
|
53
|
+
|
|
54
|
+
1. Open Terminal or Command Prompt:
|
|
55
|
+
```bash
|
|
56
|
+
pip install bda-practicals
|
|
57
|
+
```
|
|
58
|
+
2. Download any practical:
|
|
59
|
+
```bash
|
|
60
|
+
bda-5
|
|
61
|
+
# (Or bda-3, bda-6, bda-7)
|
|
62
|
+
```
|
|
63
|
+
3. Open the folder and run:
|
|
64
|
+
```bash
|
|
65
|
+
python practical_5.py
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
---
|
|
69
|
+
|
|
70
|
+
## License
|
|
71
|
+
MIT License
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
LICENSE
|
|
2
|
+
MANIFEST.in
|
|
3
|
+
README.md
|
|
4
|
+
pyproject.toml
|
|
5
|
+
setup.py
|
|
6
|
+
bda/__init__.py
|
|
7
|
+
bda/__main__.py
|
|
8
|
+
bda_package/__init__.py
|
|
9
|
+
bda_package/__main__.py
|
|
10
|
+
bda_package/downloader.py
|
|
11
|
+
bda_package/practical_3.py
|
|
12
|
+
bda_package/practical_5.py
|
|
13
|
+
bda_package/practical_6.py
|
|
14
|
+
bda_package/practical_7.py
|
|
15
|
+
bda_practicals.egg-info/PKG-INFO
|
|
16
|
+
bda_practicals.egg-info/SOURCES.txt
|
|
17
|
+
bda_practicals.egg-info/dependency_links.txt
|
|
18
|
+
bda_practicals.egg-info/entry_points.txt
|
|
19
|
+
bda_practicals.egg-info/top_level.txt
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
[console_scripts]
|
|
2
|
+
bda = bda_package.__main__:main
|
|
3
|
+
bda-3 = bda_package.__main__:cli_p3
|
|
4
|
+
bda-5 = bda_package.__main__:cli_p5
|
|
5
|
+
bda-6 = bda_package.__main__:cli_p6
|
|
6
|
+
bda-7 = bda_package.__main__:cli_p7
|
|
7
|
+
bda-all = bda_package.__main__:main
|
|
8
|
+
bda-practicals = bda_package.__main__:main
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import os
|
|
2
|
+
from setuptools import setup, find_namespace_packages
|
|
3
|
+
|
|
4
|
+
long_description = ""
|
|
5
|
+
if os.path.exists('README.md'):
|
|
6
|
+
with open('README.md', 'r', encoding='utf-8') as f:
|
|
7
|
+
long_description = f.read()
|
|
8
|
+
|
|
9
|
+
setup(
|
|
10
|
+
name='bda-practicals',
|
|
11
|
+
version='0.1.0',
|
|
12
|
+
packages=find_namespace_packages(include=['bda_package', 'bda_package.*', 'bda', 'bda.*']),
|
|
13
|
+
include_package_data=True,
|
|
14
|
+
install_requires=[], # Standard library only (hashlib, collections, etc.)
|
|
15
|
+
entry_points={
|
|
16
|
+
'console_scripts': [
|
|
17
|
+
'bda-3=bda_package.__main__:cli_p3',
|
|
18
|
+
'bda-5=bda_package.__main__:cli_p5',
|
|
19
|
+
'bda-6=bda_package.__main__:cli_p6',
|
|
20
|
+
'bda-7=bda_package.__main__:cli_p7',
|
|
21
|
+
'bda=bda_package.__main__:main',
|
|
22
|
+
'bda-all=bda_package.__main__:main',
|
|
23
|
+
'bda-practicals=bda_package.__main__:main',
|
|
24
|
+
],
|
|
25
|
+
},
|
|
26
|
+
description='A collection of Big Data Analytics (BDA) practicals with instant one-word download commands (bda-3, bda-5, bda-6, bda-7).',
|
|
27
|
+
long_description=long_description,
|
|
28
|
+
long_description_content_type='text/markdown',
|
|
29
|
+
author='Your Name',
|
|
30
|
+
author_email='your.email@example.com',
|
|
31
|
+
url='https://github.com/yourusername/bda-practicals',
|
|
32
|
+
classifiers=[
|
|
33
|
+
'Programming Language :: Python :: 3',
|
|
34
|
+
'License :: OSI Approved :: MIT License',
|
|
35
|
+
'Operating System :: OS Independent',
|
|
36
|
+
],
|
|
37
|
+
python_requires='>=3.8',
|
|
38
|
+
)
|