algorithm language-agnostic text diff
here

algorithm - Determinación del "propietario" del texto editado por múltiples usuarios



language-agnostic diff (15)

Puede haber notado que ahora mostramos un resumen de edición en las publicaciones de Wiki de la comunidad:

Wiki de la comunidad
220 revisiones, 48 ​​usuarios

También me gustaría mostrarle al usuario que "posee más" el contenido final que se muestra en la página, como un porcentaje del texto restante:

Wiki de la comunidad
220 revisiones, 48 ​​usuarios
kronoz 87%

Sí, podría haber top (n) "propietarios", pero por ahora quiero el top 1.

Supongamos que tiene esta estructura de datos, una lista de pares de usuario / texto ordenados cronológicamente para el momento de la publicación:

User Id Post-Text ------- --------- 12 The quick brown fox jumps over the lazy dog. 27 The quick brown fox jumps, sometimes. 30 I always see the speedy brown fox jumping over the lazy dog.

¿Cuál de estos usuarios es el "propietario" del texto final?

Estoy buscando un algoritmo razonable, puede ser una aproximación, no tiene que ser perfecto, para determinar el propietario. Idealmente expresado como un puntaje porcentual.

Tenga en cuenta que debemos tener en cuenta las ediciones, eliminaciones e inserciones, por lo que el resultado final parece razonable y correcto. Puede usar cualquier publicación de stackoverflow con un historial de revisión decente (no solo retapping, sino cambios frecuentes en el cuerpo del post) como un corpus de prueba. Aquí hay uno bueno, con 15 revisiones de 14 autores diferentes. Quien es el propietario"?

https://stackoverflow.com/revisions/327973/list

Haga clic en "ver fuente" para obtener el texto sin formato de cada revisión.

Debo advertirle que una solución algorítmica pura podría terminar siendo una forma del Problema del Subsistema Común más Largo . Pero como mencioné, las aproximaciones y estimaciones también están bien si funcionan bien.

Las soluciones en cualquier idioma son bienvenidas , pero prefiero las soluciones que son

  1. Bastante fácil de traducir a c #.
  2. Libre de dependencias.
  3. Pon la simplicidad antes de la eficiencia.

Es extraordinariamente raro que una publicación en SO tenga más de 25 revisiones. Pero debería "sentirse" preciso, por lo que si analizó los cambios, estaría de acuerdo con la decisión final. Te animo a que pruebes tu algoritmo en publicaciones de desbordamiento de pila con historial de revisiones y veas si estás de acuerdo con el resultado final.

Ahora he implementado la siguiente aproximación, que puede ver en acción para cada nueva revisión guardada en las publicaciones de Community Wiki

  • hacer una diferencia basada en línea de cada revisión donde cambia el texto del cuerpo
  • sumar las líneas de inserción y eliminación para cada revisión como "editcount"
  • cada ID de usuario obtiene la suma de "editcount" que contribuyeron
  • el primer autor de la revisión obtiene 2x * "editcount" como puntaje inicial, como prima principal de autoría
  • para determinar el porcentaje de propiedad final: el total de líneas editadas de cada usuario dividido por el número total de líneas editadas en todas las revisiones

(También hay algunas cláusulas de protección para condiciones simples comunes como 1 revisión, solo 1 autor, etc.) La diferencia basada en línea hace que sea bastante rápido recalcular para todas las revisiones, en un caso típico de, digamos 10 revisiones, es ~ 50ms).

Esto funciona bastante bien en mis pruebas. Se descompone un poco cuando tienes pequeñas publicaciones de 1 o 2 líneas que editan varias personas, pero creo que eso es inevitable. Aceptando la respuesta de Joel Neely como la más cercana en espíritu a lo que fui, y voté por encima de todo lo demás que parecía viable.



¿Qué tal esta idea?

  • Se muestra el nombre del póster original, hasta que la publicación haya cambiado más de x% del texto original
  • Este porcentaje se muestra como algo así como "x usuarios, y edits, z% del original"
  • La última cosa de edición actualmente presente también podría tener una cantidad de diferencia, por lo que, por ejemplo, deja en claro que la primera edición de su pregunta fue una adición menor

El punto es que después de una cierta cantidad de cambio, realmente no importa a quién pertenece. Estoy de acuerdo con los usuarios que dicen que intentar asignar "propietarios" al contenido de la wiki es contraproducente.


Así es como veo la propiedad de la publicación de ejemplo (nota, olvidé agregar etiquetas al texto, por lo que los cambios de etiqueta simples no se cuentan en este ejemplo, pero se pueden agregar fácilmente):

Frente abofeteada : Hombre, usé los números de revisión en lugar de los números de usuario. Resultados rehace a continuación:

User 38193 owns 42% (922 / 2171) of the final post User 2635 owns 28% (625 / 2171) of the final post User 116 owns 24% (529 / 2171) of the final post User 745 owns 3% (76 / 2171) of the final post User 13005 owns 0% (11 / 2171) of the final post User 18941 owns 0% (5 / 2171) of the final post User 8562 owns 0% (3 / 2171) of the final post 53 ms

De acuerdo con mi algoritmo, el usuario 38193 (@ Paul Oyster ) posee el 42% de la publicación, mientras que la publicación 2635 (@ Simucal ) tuvo el 28% y el usuario 116 (@ Mark Harrison ) el 24%, el resto es insignificante.

A partir de las https://.com/revisions/327973/list , podemos ver que Paul, que es el autor original, todavía posee la mayor parte de la pregunta, y Simucal y Mark aparecen en el n. 2 y 3. Estos corresponden a las revisiones nr. 1 (publicación original), nr. 14, que es una gran edición de Simucal, y que parece que muestra el error en mi algoritmo bastante bien (ver más abajo), y nr. 5 donde Mark agregó el script bash.

Entonces, ¿cómo llegué a esta respuesta? Bueno, el algoritmo tiene un defecto, pero volveré a hacerlo, pero así es como funciona:

Básicamente, a cada byte en la publicación original se le asigna la identificación de usuario del usuario que la escribió. Luego utilizo un algoritmo diff que puede manejar copias fuera de servicio, lo que luego traerá la identificación de usuario de los bytes copiados por un nuevo autor. Cualquier cosa agregada por un nuevo autor se le asigna la identificación de usuario del nuevo autor.

Por ejemplo, si el autor original escribe dos oraciones, éstas se etiquetarán con su identificación de usuario. Luego, otro autor lo revisa y agrega una tercera oración entre los dos originales. Para el algoritmo diff, esto parece que el nuevo autor copió la primera oración, agregó nuevos datos y copió la segunda oración. Las oraciones serán correctamente atribuidas a sus autores.

Dado que el algoritmo diff funciona en bytes, los cambios textuales menores como agregar signos de puntuación o letras faltantes deberían tener un impacto insignificante en la propiedad, y casi todo el texto original debe atribuirse al autor original. Sin embargo, en algunos casos utilizará la operación de "datos agregados" aunque se haya agregado solo un byte debido a las optimizaciones internas. El algoritmo y su implementación se crearon originalmente para manejar diffs de archivos y producir los parches más pequeños posibles entre las versiones de archivos, y a veces optimizan pequeños pasos a favor de combinarlos en una operación de hermanos si reduce el tamaño del archivo.

La falla en el algoritmo proviene de retrocesos. Observo que Jeff escribió en un comentario que las reversiones no se tendrán en cuenta, pero si un usuario edita una publicación en lugar de deshacerla, y simplemente pega las cosas anteriores, en efecto invirtiendo un cambio por parte del autor anterior, entonces todo el el texto se atribuye a la persona que "retrocede", en lugar del autor original que proporcionó la información.

El código fuente para esta implementación se puede encontrar here , para Visual Studio 2008. Tenga en cuenta que la solución no hace nada como un screenscrape ni nada, y el contenido de la publicación está codificado en la fuente en la clase TestData, escapó correctamente para las comillas, etc. Para reemplazar el texto, debe cambiar ese archivo o implementar una forma de leer los contenidos desde fuera del programa.

De todos modos, aquí está el algoritmo en un poco más de detalle.

  1. Cree una matriz de enteros, siempre que la revisión original (en realidad, la codifiqué en bytes a través de UTF8, y esta es la longitud que utilicé). Llene esta matriz con la identificación de usuario del autor original que ahora posee el 100% de la revisión, cada carácter / byte es su
  2. Compare la primera revisión con la próxima revisión. Esta comparación producirá una lista de operaciones. Estas operaciones se pueden usar para tomar la revisión original, aplicarle las operaciones y obtendrá la próxima revisión (más sobre esto a continuación).
  3. Imagine que la publicación original es la matriz de ID de usuario que ha preparado (la que actualmente solo contiene un grupo de valores igual al ID del primer autor), y aplique las operaciones a esto. Esto producirá una nueva lista de identificadores, algunos de ellos serán el autor original, otros serán el segundo autor.
  4. Guarde la segunda revisión y esta nueva lista de ID de usuario, y ejecute los pasos 2 + 3 entre estos datos, y la próxima revisión, y la siguiente revisión, etc. hasta que llegue al final

En este punto, tienes una lista de identificadores de usuario que te dice qué usuario agregó cada personaje.

Las operaciones de la comparación es una de dos:

  • Insertar nuevos bytes
  • Copia algunos bytes

La forma en que se utiliza el resultado de la comparación es que toma los contenidos anteriores (la primera publicación) y le aplica las operaciones, y luego produce la próxima revisión. Es básicamente un diff.

Cuando aplico las operaciones a mi lista de identificadores de usuario, cuando copio, simplemente copio, cuando inserto, siempre inserto una cantidad de identificadores igual a la longitud almacenada en la operación.

Déjame dar un ejemplo:

Publicación original:

This is the first post

Siguiente publicación:

This is the next post, it is based on the first post.

La lista de operaciones sería así:

  1. Copie 12 caracteres ''Este es el''
  2. Insertar ''siguiente''
  3. Copia 5 caracteres ''publicación''
  4. Inserta 17 caracteres '', está basado en''
  5. Copia 14 caracteres ''la primera publicación''
  6. Inserta 1 caracter ''.''

Si en cambio trabajo con las identificaciones de usuario, primero tendría esta matriz:

0000000000000000000000 This is the first post

Ahora aplico las operaciones, y para cada inserción, inserto un 1 en su lugar:

00000000000011110000011111111111111111000000000000001 This is the next post, it is based on the first post.

Ahora simplemente cuento cuántos 0 y 1 tengo:

  1. 0''s: 31
  2. 1''s: 22

El usuario 0 posee 31 / (31 + 22) de la publicación, y el usuario 1 posee 22 / (31 + 22) de la publicación.

Traducido a porcentajes: el usuario 0 posee el 58%, el usuario 1 posee el 42%.

Ahora, el problema con este algoritmo es el de los retrocesos y la adición de contenido perdido / borrado.

Por ejemplo, si tiene usuarios A, B y C, y el usuario A publica algo que realmente desactiva al usuario B, el usuario B ingresa y borra todo, y agrega solo "THIS IS CRAP". Cuando el usuario C ve esto, edita la publicación y vuelve a agregar todo lo que A publicó, posiblemente con correcciones. El usuario C ahora posee el 100% de la publicación.

Sin embargo, no sé cómo resolver el problema anterior.

Voy a publicar el código que hace esto más tarde esta noche si es interesante.

Aplicado al ejemplo de ''zorro café rápido'', volviendo a numerar los usuarios a 1-3, obtengo esto:

User 3 owns 75% (45 / 60) of the final post User 1 owns 25% (15 / 60) of the final post

Tenga en cuenta que el usuario 2, que solo agregó la parte "a veces", que se eliminó posteriormente, se elimina de la lista.

Los id para las publicaciones son como tales:

The quick brown fox jumps over the lazy dog. 11111111111111111111111111111111111111111111 (44 = 100%) The quick brown fox jumps, sometimes. 1111111111111111111111111222222222222 (25 / 12 ~ 68% / 32%) I always see the speedy brown fox jumping over the lazy dog. 333333333333333333333331111111111111113333333333333333333333 (45 / 15 = 75% / 25%)

Cosas que el algoritmo enfrentará:

Si copio algo al hacer mi nueva publicación, el algoritmo atribuirá correctamente los elementos copiados, incluso si ahora copio partes de las que también agregué. Ejemplo:

This is the first post, which is cool 1111111111111111111111111111111111111 This is the second post, which is the second post. 11111111111122222211111111111111112222222222111111 ^-- copied ------^

El único problema con este algoritmo, y esta publicación en su totalidad es que no estoy del todo seguro de que produzca lo que yo llamaría un resultado intuitivamente justo. Podría ser, acabo de hackear el programa, pero probablemente sea necesario realizar más pruebas con muchos casos extremos para determinar si realmente produce algo que la gente aceptaría.

Además, si solo muevo cosas desde la publicación inicial, solo bits pequeños, como un pequeño porcentaje, serán míos. Dado que el algoritmo es un algoritmo de diferencias en el fondo, a veces el costo de generar una operación de copia para solo 1 o un par de bytes supera el costo de simplemente insertarlo en bruto, por lo que a veces se tratará una secuencia corta de bytes como insertada, aunque podrían haber sido copiados de la publicación original.


Creo que la idea es fundamentalmente defectuosa.

Si alguien escribe un análisis brillante con ortografía horrible y ejemplos poco claros, y copio la edición extensamente, ¿he creado el 60% del trabajo? Claramente no; el resultado es un derivado donde la mayor parte del valor proviene del cartel inicial. No es posible una medida útil basada en el recuento de caracteres o de palabras, pero requiere un fuerte análisis semántico a nivel de IA.

Aparte de eso, buscar crédito basado en la "propiedad" de los artículos probablemente sería completamente inútil y anti-wiki. En Wikipedia, por ejemplo, las personas que actúan como si tuvieran artículos son una de las influencias más dañinas.


El concepto inicial debe tener un peso. Las correcciones ortográficas deben tener un peso. La gramática / estructura debe tener un peso. La redacción debe tener un peso. La concisión debe tener un peso. Etc ...

Los pesos son la única manera justa de hacerlo pero también imposible de determinar.


El número de personajes es complicado.

Qué tal si:

Break latest revision into a set of sentences. //Sentence is any text fragment surrounded by punctuation For each Sentence Find which user created that sentence. Add 1 to the user who created the sentence Add 1 to the number of sentences For Each user % ownership = Count for that user / Number of sentences.

Encontrar qué usuario creó esa oración.
Hacer coincidir la oración con la revisión es fácil si quieres una coincidencia exacta, pero estaría más contento con una coincidencia parcial.

Para hacer esta coincidencia parcial ...

Elimine las palabras comunes del fragmento de la oración y busque ese fragmento eliminado en una versión eliminada de cada revisión. El primer golpe es la oración escrita por el propietario.

Opciones: (en lugar de eliminar palabras comunes)

  • Para cada palabra en la oración, condense cada palabra al primer y al último caracteres. Esto explicará los errores ortográficos, etc.
  • Solo usa la primera y las últimas dos palabras en el fragmento de la oración.
  • Hacer coincidir el 80% de las palabras probablemente sea lo suficientemente bueno para atribuir la propiedad. (Esto es algo difícil de hacer para la computadora, y no se puede almacenar en caché)

Despojando palabras comunes

Ya haces esto para buscar, entonces las bibliotecas, etc. ya están allí. Incluso si usa la fórmula de alguien más, quizás debería CommonWordStrip cada revisión antes de comenzar.


Es una wiki, ¿por qué no dejar que cada editor elija el significado de su cambio? Proporcione un menú desplegable con algo como ...

Por favor califique su edición:

  1. Algunas ediciones menores (ortografía, gramática, etc.)
    • Muchas ediciones menores
    • Algunas ediciones importantes (cambios en hechos específicos, cifras, etc.)
    • Muchas ediciones importantes
    • Algunas modificaciones importantes (cambios en la tesis, conclusión, etc.)
    • Muchas ediciones principales

Luego use las respuestas combinadas para estimar la propiedad.


Esto funcionará si quiere implementar / aprovechar un algoritmo diff de la difflib de Python - probablemente tendrá que hacer algún tipo de diferencia en cualquier caso. Este fragmento llama al usuario con la mayor cantidad de texto al ganador.

Disculpe mi hardcoding.

#!/usr/bin/env python import collections import difflib import logging import pprint import urllib2 import re class OwnageDeterminer(object): add_coefficient = 1 remove_coefficient = .5 def __init__(self, edits): self.edits = edits self.counts_by_username = {} def __call__(self): edits, counts_by_username = self.edits, self.counts_by_username for i, edit in enumerate(edits): username = edit[''username''] unique_counts = {''added'': 0, ''removed'': 0} existing_text = edits[i-1][''text''] if i > 0 else '''' new_text = edits[i][''text''] for char_diff in difflib.ndiff(existing_text, new_text): if char_diff.startswith(''+''): unique_counts[''added''] += 1 elif char_diff.startswith(''-''): unique_counts[''removed''] += 1 user_counts = counts_by_username.get(username, collections.defaultdict(int)) user_counts[''removed''] += self.remove_coefficient * unique_counts[''removed''] user_counts[''added''] += self.add_coefficient * unique_counts[''added''] counts_by_username[username] = user_counts winner = None winning_score = 0 score_by_username = {} for username, counts in counts_by_username.iteritems(): score = counts[''removed''] + counts[''added''] if score > winning_score: winner = username winning_score = score score_by_username[username] = score logging.debug(''Scores: %s'', pprint.pformat(score_by_username)) return winner if __name__ == ''__main__'': logging.basicConfig(level=logging.DEBUG) site = urllib2.urlopen(''http://.com/revisions/327973/list'') contents = site.read() regex = re.compile(r''(/revisions/viewmarkup//d+).*?/users//d+/([/w-]+)'', re.MULTILINE|re.DOTALL) revisions = regex.findall(contents) print revisions edits = [] for reluri, username in sorted(revisions, key=lambda t: t[0]): text = urllib2.urlopen(''http://.com{0}''.format(reluri)).read() edit = {''username'': username, ''text'': text} edits.append(edit) od = OwnageDeterminer(edits) print od()

La salida:

DEBUG:root:Scores: {''blorgbeard'': 0.5, ''dave-markle'': 0.5, ''dbr'': 1172.0, ''gatekiller'': 69.5, ''joseph-ferris'': 0.0, ''lkessler'': 0.0, ''mark-harrison'': 592.0, ''mdb'': 3.0, ''onebyone-livejournal-com'': 0.0, ''paul-oyster'': 482.0, ''rob-wells'': 0.0, ''simucal'': 1070.5, ''skiphoppy'': 0.0, ''thesoftwarejedi'': 701.0} dbr

Difflib documenta en complejidad:

Sincronización: el algoritmo básico de Ratcliff-Obershelp es el tiempo cúbico en el peor de los casos y el tiempo cuadrático en el caso esperado. SequenceMatcher es el tiempo cuadrático para el peor de los casos y tiene el comportamiento esperado de casos de una manera complicada sobre cuántos elementos tienen las secuencias en común; el mejor caso de tiempo es lineal.

Otra cosa agradable es que este cálculo ganador es lineal, por lo que puede almacenar en caché los resultados originales y realizar actualizaciones incrementales en nuevas ediciones, a pesar de la gran carga de inicialización.


La clave para tener una buena solución a este problema es obtener información adicional sobre lo que está sucediendo con la edición. La información adicional disponible en este medio es la tasa de votación y respuesta a las preguntas. Entonces, si alguien realiza una edición que lleva a la pregunta obtener muchos votos ascendentes, comentarios y respuestas, su edición fue muy valiosa. Casos especiales probablemente existen para una nueva pregunta sin respuesta que se edita antes de que haya estado en el sitio durante mucho tiempo.

Debes ver cuánto ha cambiado la publicación usando el algoritmo de distancia de Levenshtein y luego ponderar su edición por la cantidad de votos, comentarios y respuestas que recibe la pregunta después de su edición.

Let n = total revisions Let m = the revision number of a poster Let post[it] = array with text of post at revision ''it'' Let votes[it] = votes that revision ''it'' received (also add bonus for comments/answers) value = 0 for (it = m; it < n; ++it) { value += (Levenshtein(post[it-1], post[m]) / average_length_post) * (votes[it]) }

Si calcula el valor para cada publicación, la propiedad de una publicación es el valor total de todas las ediciones de ese usuario dividido por la suma de todos los valores de edición para esa publicación.


Nadie lo posee. Otorgar propiedad viola el espíritu de "comunidad wiki" y puede llevar a guerras de edición contraproducentes.


No estoy seguro de si es posible, pero podría contar la cantidad de caracteres añadidos.

Ejemplo:

  • El usuario 1 envía una pregunta con 400 caracteres (el usuario 1 tiene 400 de 400)
  • El usuario 2 elimina 40 y agrega 60 (el usuario 1 tenía 360 y el usuario 2 tenía 60)

Si revierte, también debería volver al recuento anterior de usuario / personaje.

Pero ... tal vez es más simple y más justo nombrar el póster original ...

Pensándolo bien, edito mucho, pero nunca me considero "propietario" del tekst porque solo modifico la presentación (formato y gramática) pero no los contenidos.


Por la parte superior de mi cabeza haría algo como esto:

  • Creo que contar palabras en lugar de líneas o caracteres tiene sentido
  • Tokenize la revisión original en palabras, y adjunte el autor a cada
  • Paso a paso por el historial de revisiones y, a medida que se agregan palabras, adjunte el autor.
  • Si las palabras son borradas, solo olvídalas.
  • Si se cambian las palabras, puede contarlas como eliminar / insertar, o tener algún tipo de umbral basado en caracteres para que las correcciones ortográficas no se atribuyan a un nuevo autor.
  • Terminas con una lista de palabras en contra de quién los escribió originalmente

Si entiendo su pregunta correctamente, parece que está tratando de hacer lo que IBM hizo hace un tiempo con un proyecto de investigación de Wikipedia. A saber, ver quiénes son las revisiones del texto que fueron más aceptadas por otros usuarios y cómo el texto general cambió con el tiempo. El nombre del proyecto fue el flujo de historia y el flujo de la historia: la forma en que funciona proporciona una descripción bastante buena de cómo funcionaba su algoritmo.


Una pregunta es si eliminar caracteres es tan válido como agregarlos. Usar Diff puede funcionar bien, pero no siempre se sigue que la persona que ha agregado más es el editor más válido (algunas personas pueden escribir en 10 caracteres lo que otros toman en una página para escribir).

Entonces creo que tienes dos factores aquí:

  • Cantidad de cambio
  • Calidad del cambio

Por lo tanto, estaría tentado de escribir algo que simplemente traduzca palabras agregadas / eliminadas a una puntuación. Agregando a esto algún tipo de factor de calidad (esto tendría que ser un parámetro externo) y el valor combinado podría ser utilizado en la clasificación.

Podría decirse que podría generar algún tipo de "factor de calidad" primitivo en función de la distancia que tomó antes de que se editara un elemento. Por lo tanto, si algo que escribí no se modificó hasta la 12ª edición, entonces no podría haber sido demasiado incorrecto (en relación con algo de menos calidad cambió tan pronto como se agregó).


Vimos tu tweet antes. Desde la pantalla del enlace 327973, parece que ya tiene un diff de un solo paso en su lugar. Basado en eso, me enfocaré en la composición de edición múltiple:

  1. A, el póster original posee el 100% de la publicación.

  2. Cuando B, un segundo póster, realiza ediciones tales que, por ejemplo, el 90% del texto no se modifica, la propiedad es A: 90%, B: 10%.

  3. Ahora C, un tercero, cambia el 50% del texto. (A: 45%, B: 5%, C: 50%)

    En otras palabras, cuando un póster realiza ediciones tales que x% se modifica ey = (100-x)% no se modifica, entonces ese póster ahora posee x% del texto y toda la propiedad anterior se multiplica por y%.

    Para hacerlo interesante, ahora supongamos ...

  4. A hace una edición del 20%. Entonces A posee un "nuevo" 20%, y las propiedades residuales se multiplican ahora en un 80%, quedando (A: 36%, B: 4%, C: 40%). La propiedad "neta" es por lo tanto (A: 56%, B: 4%, C: 40%).

Aplicando esto a su espécimen (327973) con todo redondeado al porcentaje más cercano:

Versión 0: la publicación original.

  • Paul Oyster: 100%

Versión 1: su herramienta diff actual muestra una adición pura de texto, por lo que todos esos caracteres pertenecen al segundo póster.

  • Paul Oyster: 91%
  • onebyone: 9%

Versión 2: el diff muestra el reemplazo de una palabra. La nueva palabra pertenece al tercer póster y el resto pertenece a los carteles anteriores.

  • Paul Oyster: 90%
  • onebyone: 9%
  • Blogbeard: 1%

Versión 3: edición de solo etiqueta. Como tu pregunta era sobre el texto, ignoro las etiquetas.

  • Paul Oyster: 90%
  • onebyone: 9%
  • Blogbeard: 1%

Versión 4: Adición de texto.

  • Paul Oyster: 45%
  • onebyone: 4%
  • Blogbeard: 1%
  • Mark Harrison: 50%

Espero que eso sea suficiente para dar sentido a esta propuesta. Tiene un par de limitaciones, pero estoy deslizando estas en su declaración de que una aproximación es aceptable. ;-)

  1. Distribuye bruta y forzosamente el efecto del cambio entre todos los propietarios anteriores. Si A publica, B hace una adición pura, y C edita la mitad de lo que B agregó, este enfoque simplista simplemente aplica la propiedad de C en toda la publicación, sin tratar de analizar qué propiedad anterior se modificó más.

  2. Representa las adiciones o cambios, pero no otorga ningún crédito de propiedad para la eliminación, porque el eliminador agrega 0% al texto restante. Usted puede considerar esto como un error o una característica. Elegí la puerta número 2.

Actualización: un poco más sobre el número 1 anterior. Creo que hacer un seguimiento completo de la propiedad de la parte de una publicación editada requeriría una de dos cosas (el margen de la página web no es lo suficientemente grande para una prueba formal ;-):

  • Cambiar la forma en que se almacena el texto para reflejar la propiedad de porciones individuales del texto (por ejemplo, A posee las palabras 1-47, B posee las palabras 48-59, A posee las palabras 60-94, ...), aplicando el "cuánto queda" acercar en mi propuesta a cada parte y actualizar los datos de propiedad de la porción.

  • Teniendo en cuenta todas las versiones del primero al actual (en efecto, volver a calcular los datos de propiedad de la parte sobre la marcha).

Así que este es un buen ejemplo de una compensación entre una aproximación rápida y sucia (a costa de la precisión), un cambio en toda la base de datos (a costa del espacio), o cada cálculo que tiene que mirar la totalidad historia (a costa del tiempo).