Repository: jina-ai/jina
Issue: from_csv not robust for real-world datasets

**Describe the bug**
I'm having major trouble with `from_csv`. 

Context: I'm writing tutorial for build simple text search engine with Jina + Hub. I don't want to include a whole section of processing datasets, hence just passing a CSV into `from_csv`. I tried with meme dataset (converted tsv) before, and now using [superhero dataset](https://www.kaggle.com/jonathanbesomi/superheroes-nlp-dataset) (native csv). Still getting same issues.

**What I want to do**:
`Document.text` to be populated from the field `powers_text`
`Document.tags` to be every other field in the record

**My code:**

```python
with flow, open("data/superheroes.csv") as fp:
    flow.index(from_csv(fp, field_resolver={"powers_text": "text"}), size=10)
```

**Expected result**:

- Clean load of each row of CSV as individual Document
- Any escaping/quoting handled automatically

**Actual result**:

```
ina.excepts.BadDocType: fail to construct a document from {'name': '3-D Man', 'real_name': 'Delroy Garrett, Jr.', 'full_name': 'Delroy Garrett, Jr.', 'overall_score': '6', 'history_text': "D
elroy Garrett, Jr. grew up to become a track star and competed in the Olympic Games. After he tested positive for steroids, he lost his three gold medals. In despair, he turned to religion, s
pecifically the Triune Understanding. This group's founder, Jonathan Tremont, had found one of three fragments of a mysterious object and used it to give Garrett the powers of 3-D Man. Garret
t assumed that his powers were because of his newfound spiritual enlightenment, and Tremont never disabused him of the notion.", 'text': '', 'intelligence_score': '85', 'strength_score': '30'
, 'speed_score': '60', 'durability_score': '60', 'power_score': '40', 'combat_score': '70', 'superpowers': "['Super Speed', 'Super Strength']", 'alter_egos': '[]', 'aliases': "['']", 'place_o
f_birth': '', 'first_appearance': '', 'creator': 'Marvel Comics', 'alignment': 'Good', 'occupation': '', 'base': '', 'teams': "['Annihilators', 'Asgardians', 'Avengers', 'New Avengers']", 're
latives': '', 'gender': 'Male', 'type_race': 'Human', 'height': '-', 'weight': '-', 'eye_color': '', 'hair_color': '', 'skin_color': '', 'img': '/pictures2/portraits/11/050/10038.jpg?v=156096
9486', 'has_electrokinesis': '0.0', 'has_energy_constructs': '0.0', 'has_mind_control_resistance': '0.0', 'has_matter_manipulation': '0.0', 'has_telepathy_resistance': '0.0', 'has_mind_contro
l': '0.0', 'has_enhanced_hearing': '0.0', 'has_dimensional_travel': '0.0', 'has_element_control': '0.0', 'has_size_changing': '0.0', 'has_fire_resistance': '0.0', 'has_fire_control': '0.0', '
has_dexterity': '0.0', 'has_reality_warping': '0.0', 'has_illusions': '0.0', 'has_energy_beams': '0.0', 'has_peak_human_condition': '0.0', 'has_shapeshifting': '0.0', 'has_heat_resistance': '
0.0', 'has_jump': '0.0', 'has_self-sustenance': '0.0', 'has_energy_absorption': '0.0', 'has_cold_resistance': '0.0', 'has_magic': '0.0', 'has_telekinesis': '0.0', 'has_toxin_and_disease_resis
tance': '0.0', 'has_telepathy': '0.0', 'has_regeneration': '0.0', 'has_immortality': '0.0', 'has_teleportation': '0.0', 'has_force_fields': '0.0', 'has_energy_manipulation': '0.0', 'has_endur
ance': '0.0', 'has_longevity': '0.0', 'has_weapon-based_powers': '0.0', 'has_energy_blasts': '0.0', 'has_enhanced_senses': '0.0', 'has_invulnerability': '0.0', 'has_stealth': '0.0', 'has_mark
smanship': '0.0', 'has_flight': '0.0', 'has_accelerated_healing': '0.0', 'has_weapons_master': '0.0', 'has_intelligence': '0.0', 'has_reflexes': '0.0', 'has_super_speed': '1.0', 'has_durabili
ty': '0.0', 'has_stamina': '0.0', 'has_agility': '0.0', 'has_super_strength': '1.0'}, if you are trying to set the content you may use "Document(content=your_content)"
```

**Describe how you solve it**

Write a CSV loader by hand, using Python's `csv` library. Which works right away out of the box, so I think `from_csv` should be able to work better.

```python
docs = DocumentArray()

with open("data/superheroes.csv", "r") as data:
    reader = csv.reader(data, delimiter=",")
    for line in csv.DictReader(data):
        doc = Document(text=line["powers_text"])
        doc.tags = line
        docs.append(doc)
```

**Nice to haves**

While we're at it, it'd be really nice to have a `delimiter` parameter so we could use `from_csv('foo.csv', delimiter='\\t') to load TSVs etc

---

<!-- Optional, but really help us locate the problem faster -->

**Environment**
<!-- Run `jina --version-full` and copy paste the output here -->

**Screenshots**
<!-- If applicable, add screenshots to help explain your problem. -->

Changed files:
jina/types/document/generators.py

diff --git a/jina/types/document/generators.py b/jina/types/document/generators.py
index 02404cfba8f..3febd7b006d 100644
--- a/jina/types/document/generators.py
+++ b/jina/types/document/generators.py
@@ -104,6 +104,7 @@ def from_csv(
     field_resolver: Optional[Dict[str, str]] = None,
     size: Optional[int] = None,
     sampling_rate: Optional[float] = None,
+    delimiter: Optional[str] = ",",
 ) -> Generator['Document', None, None]:
     """Generator function for CSV. Yields documents.
 
@@ -113,12 +114,13 @@ def from_csv(
             a JSON string or a Python dict.
     :param size: the maximum number of the documents
     :param sampling_rate: the sampling rate between [0, 1]
+    :param delimiter: the character that separates fields in your CSV file
     :yield: documents
 
     """
     from ..document import Document
 
-    lines = csv.DictReader(fp)
+    lines = csv.DictReader(fp, delimiter=delimiter)
     for value in _subsample(lines, size, sampling_rate):
         if 'groundtruth' in value and 'document' in value:
             yield Document(value['document'], field_resolver), Document(