diff --git a/.obsidian/workspace.json b/.obsidian/workspace.json
index 0b18e8c..2d42481 100644
--- a/.obsidian/workspace.json
+++ b/.obsidian/workspace.json
@@ -44,7 +44,7 @@
"autoReveal": false
},
"icon": "lucide-folder-closed",
- "title": "Files"
+ "title": "Explorador de archivos"
}
},
{
@@ -78,8 +78,7 @@
}
],
"direction": "horizontal",
- "width": 300,
- "collapsed": true
+ "width": 300
},
"right": {
"id": "3ad564d399e497ab",
@@ -172,32 +171,31 @@
},
"left-ribbon": {
"hiddenItems": {
- "bases:Create new base": false,
- "switcher:Open quick switcher": false,
- "graph:Open graph view": false,
- "canvas:Create new canvas": false,
- "daily-notes:Open today's daily note": false,
- "templates:Insert template": false,
- "command-palette:Open command palette": false,
+ "switcher:Abrir selector rápido": false,
+ "graph:Abrir vista gráfica": false,
+ "canvas:Crear nuevo lienzo": false,
+ "daily-notes:Abrir la nota de hoy": false,
+ "templates:Insertar plantilla": false,
+ "command-palette:Abrir paleta de comandos": false,
+ "bases:Crear nueva base": false,
"table-editor-obsidian:Advanced Tables Toolbar": false,
"obsidian-git:Open Git source control": false
}
},
"active": "f76c0dfd568461ec",
"lastOpenFiles": [
+ "CUARTO/PHAE/Teoria_2526.md",
+ "CUARTO/AII/Teoria_2526.md",
"Pasted image 20260224113246.png",
"Pasted image 20260224112101.png",
"Pasted image 20260224110141.png",
"Pasted image 20260217115003.png",
- "CUARTO/PHAE/Teoria_2526.md",
"Pasted image 20260210134109.png",
"Pasted image 20260210131013.png",
"Pasted image 20260210130956.png",
"Pasted image 20260210125017.png",
- "CUARTO/AII/Teoria_2526.md",
"Pasted image 20260205135941.png",
"Pasted image 20260205135914.png",
- "Pasted image 20260129132034.png",
"CUARTO/AII/Presentacion.md",
"CUARTO/PHAE",
"CUARTO/SSII/Teoria_2526.md",
diff --git a/CUARTO/AII/Teoria_2526.md b/CUARTO/AII/Teoria_2526.md
index 52045f0..76ba44d 100644
--- a/CUARTO/AII/Teoria_2526.md
+++ b/CUARTO/AII/Teoria_2526.md
@@ -169,4 +169,163 @@ Hacemos lo mismo con las queries, representarlas como vectores en el espacio.
#### Distancia Euclídea
No es buena idea puesto que si dos vectores se superponen (porque son el mismo documento) pero tienen distinto módulo va a salir que hay distancia de un documento consigo mismo.
#### Mejor: usar el ángulo
-Para usar el ángulo tenemos que normalizar los vectores volviéndolos unitarios y entonces podemos comparar la proximidad mediante el ángulo entre ellos.
\ No newline at end of file
+Para usar el ángulo tenemos que normalizar los vectores volviéndolos unitarios y entonces podemos comparar la proximidad mediante el ángulo entre ellos.
+# Whoosh
+## 1. Introducción
+Whoosh sólo funciona con caracteres unicode. El workflow es el mismo siempre:
+1. Crear un schema con los tipos de los datos que tendrá el índice
+ - Con `stored=True` en los tipos, se indica los campos que se almacenarán. Solamente los campos que estén almacenados se mostrarán en `print` o similares.
+1. Crear el indexador
+2. Crear el writer
+3. Añadir documentos al writer (y commit)
+### Ejemplo de búsqueda
+```python
+with ix.searcher() as searcher:
+ query = QueryParser("content", ix.schema).parse("hola") # contenido a buscar
+ results = searcher.search(query)
+ results[0]
+```
+## 2. Diseño del schema
+### Tipos
+- **`TEXT`**: por defecto almacena la posición de cada término indexado por si hay que buscar por frases. Si no hace falta buscar por frases, mejor pasarle `phrase=False`.
+- **`KEYWORD`**: para keywords separadas por `,` se usa `KEYWORD`. Se puede especificar si está separado por comas con `commas=True` (por defecto está separado por `' '`). También se puede usar `lowercase=True` para convertirlo a minúsculas automáticamente. Por último, `scorable=True` es por si el campo se usará para buscar.
+- **`ID`**: se indexan sin dividirse en términos. No vale para el ranking. Se usa para la url, el path, la fecha, etc. Por defecto tienen `stored=False`.
+- **`STORED`**: se almacena pero ni se indexa ni se puede buscar en él. Se suele usar para información que se mostrará solamente.
+- **`NUMERIC`**: para números
+- **`DATETIME`**: para fechas
+- **`BOOLEAN`**: para booleanos. Permite buscar por `'yes'`, `'no'`, `'true'`, `'false'`, `1`, `0`, `'t'` o `'f'`.
+### Creando un schema
+```python
+schema = Schema(from_addr=ID(stored=True),
+ to_addr=ID(stored=True),
+ subject=TEXT(stored=True),
+ body=TEXT(analyzer=StemmingAnalyzer()),
+ tags=KEYWORD)
+```
+### Modificando el schema después de indexar
+```python
+writer = ix.writer()
+writer.add_field("fieldname", fields.TEXT(stored=True))
+writer.remove_field("content")
+writer.commit()
+```
+Con `optimize=True` en el commit, se hace el borrado físico de los datos eliminados con `.remove_field()`.
+### Campos dinámicos
+Son campos cuyos valores se capturarán mediante regex. Se crean así:
+```python
+schema.add("*_d", fields.DATETIME(stored=True), glob=True)
+```
+### Dando pesos a los campos para el ranking
+Con el atributo `field_boost` podemos darle más valor a un campo que a otro para la búsqueda rankeada.
+## 3. Indexando documentos
+Para crear un índice usamos:
+```python
+ix = index.create_in("indexdir", schema)
+```
+Y para buscar en uno ya creado:
+```python
+ix = index.open_dir("indexdir")
+```
+Para añadir documentos al índice ya creado, se crea un writer y se añaden documentos.
+```python
+writer.add_document(title=u"Title to be indexed", _stored_title=u"Stored title")
+```
+En realidad, un índice creado por `filedb` es un contenedor de varios subíndices llamados segmentos. Para borrar documentos se puede borrar de varias formas:
+ ```python
+delete_by_term(fieldname, termtext)
+delete_by_query(query)
+ ```
+ Para actualizar documentos es obligatorio que haya un campo `unique=True`, **aunque esto no hace que no se pueda repetir (no tiene que ver con las KEY de BBDD relacionales)**. La función para actualizar:
+ ```python
+ writer.update_document(path=u"/a", content="Replacement for the first document")
+ ```
+## 4. Buscando en el índice
+Se usa un objeto Searcher para buscar:
+```python
+qp = QueryParser("content", schema=myindex.schema)
+q = qp.parse(u"hello world")
+
+with myindex.searcher() as s:
+ results = s.search(q)
+```
+Se le puede poner `limit` a la query para que de mas de los 10 resultados rankeados por defecto que devuelve. Con `limit=None` devuelve todos.
+### Objeto Results
+Es una lista de dicts. Tiene varias funciones para ver el número de resultados sin rankear o rankeados.
+```python
+found = results.scored_length()
+if results.has_exact_length():
+ print("Scored", found, "of exactly", len(results), "documents")
+else:
+ low = results.estimated_min_length()
+ high = results.estimated_length()
+
+ print("Scored", found, "of between", low, "and", high, "documents")
+```
+### Algoritmos de ranking
+```python
+with myindex.searcher(weighting=scoring.TF_IDF()) as s:
+ ...
+```
+### Filtrando
+```python
+with myindex.searcher() as s:
+ qp = qparser.QueryParser("content", myindex.schema)
+ user_q = qp.parse(query_string)
+
+ # Only show documents in the "rendering" chapter
+ allow_q = query.Term("chapter", "rendering")
+ # Don't show any documents where the "tag" field contains "todo"
+ restrict_q = query.Term("tag", "todo")
+
+ results = s.search(user_q, filter=allow_q, mask=restrict_q)
+```
+## 5. Parseando queries
+- En las queries se pueden usar operadores como `AND` o `OR`. Por defecto es `AND`, pero si queremos que sean `OR` sin ponerlos, se puede hacer así:
+```python
+parser = qparser.QueryParser(fieldname, schema=myindex.schema,
+ group=qparser.OrGroup)
+```
+- Para buscar en varios campos:
+```python
+mparser = MultifieldParser(["title", "content"], schema=myschema)
+```
+- Para buscar frases se debe poner la query entre `""`.
+- También se puede usar `~X` para ver si una palabra está `X` palabras después (`whoosh library~5`).
+- Si no se pone `campo:valor` buscará siempre en el campo por defecto.
+- Para términos inexactos se usan patrones que usan `?` para un sólo caracter y `*` para varios (**se aplican solo a palabras no a frases**).
+- Para rangos, se usa `TO`. Se pueden usar también para fechas (formato por defecto: YYYYMMDD).
+ ```
+ date:[20050101 TO 20090715]
+ [0000 TO 0025}
+ {prefix TO suffix}
+ [0025 TO]
+ {TO suffix}
+ ```
+ - Se puede especificar el peso de la palabra independientemente del campo en el que aparezca con `^X` donde `X` es el peso.
+## 6. Otros formatos de fecha
+Con el `DateParserPlugin` (que se añade al QueryParser con `.add_plugin(DateParserPlugin())`) se puede buscar por varias cosas:
+```
+20050912
+2005 sept 12th
+june 23 1978
+23 mar 2005
+july 1985
+sep 12
+today
+yesterday
+tomorrow
+now
+next friday
+last tuesday
+5am
+10:25:54
+23:12
+8 PM
+4:46 am oct 31 2010
+last tuesday to today
+today to next friday
+jan 2005 to feb 2008
+-1 week to now
+now to +2h
+-1y6mo to +2 yrs 23d
+```