Autor Thema: Ideenfindung für Import  (Gelesen 4051 mal)

Offline MarkusL

  • Aktives Mitglied
  • ***
  • Beiträge: 124
  • Geschlecht: Männlich
Ideenfindung für Import
« am: 25.09.12 - 13:50:21 »
Hallo zusammen,

an mich ist die Bitte herangetragen worden, eine Excel-Tabelle durch eine Notes-DB abzulösen, da hierdurch viele Vorteile gegeben sind.
Im Moment steht der Umsetzung gedanklich nur ein unregelmäßiger Import von Daten aus einer txt-Datei entgegen.
Jetzt hoffe ich in diesem Forum auf eine Anregung.

In der Datenbank sind derzeit ca. 4.500 Datensätze.
Bei jedem ca. halbjährlichen Import kommen ca. 300 - 500 Datensätze hinzu.
Bei dem Import müsste anhand von einer eindeutigen Kundennummer und einer weiteren eindeutigen Nummer geprüft werden, ob dieser Datensatz bereits existiert.
Wenn ja, soll der bestehende mit neuen Infos ergänzt werden,
wenn nein, soll der Datensatz neu angelegt werden.

In meiner ersten Überlegung habe ich mir gedacht, ich mache das mit einer Schleife, die alle Dokumente in der DB durchgeht und diese mit einer zweiten Schleife mit allen neuen Daten vergleicht. Das bedeutet über 1,3 Mio Berechnungen - Tendenz steigend.
Zum Zeitpunkt der Überlegung kannte ich die Anzahl der Daten noch nicht.

Gibt es hierbei eventuell lange Laufzeiten oder sonstige Probleme, auf die ich stoßen könnte?
Gibt es einen besseren und vor allen Dingen schnelleren Lösungsansatz.

Bin für alle Anregungen dankbar.

Gruß Markus
« Letzte Änderung: 25.09.12 - 15:14:27 von MarkusL »
Version Lotus Notes / Domino: 8.5.3
Server: 1 Cluster, 1 weiterer Server
Anzahl Benutzer: ca. 230

klaussal

  • Gast
Re: Ideenfindung für Import
« Antwort #1 am: 25.09.12 - 14:05:32 »
Du kannst doch mit GetDocumentbyKey prüfen, ob die KdNr bereits vorhanden ist.
Wenn ja, update, wenn nicht, neu anlegen.

Offline Fineas

  • Aktives Mitglied
  • ***
  • Beiträge: 145
  • Geschlecht: Männlich
  • PCLP Dev/Admin 5,6,7,8
Re: Ideenfindung für Import
« Antwort #2 am: 25.09.12 - 14:09:31 »
Hallo,
wenn Du Die Rechnerei sparen willst:
- erstmal immer alle neuen Datensätze mit Import-Zeitstempel als NEU importieren, aber nicht öffentlich anzeigen
- danach einmal über eine Ansicht laufen (ViewEntryCollection), in der alle Dokumente NEU und ALT nach ID und Zeitstempel sortiert drin sind
- jetzt beim Durchlauf gucken, ob der Vorgänger ein vorhandener Datensatz oder neu ist und entsprechend behandeln
- entweder die ALT Datensätze aktualisieren oder durch die NEU Datensätze ersetzen
- die Importdatensätze archivieren, dannst hast Du gleich was zur Revision
- fertig
- Vorteil: bei einem Abbruch kannst Du immer wieder laufen lassen und das System arbeitet weiter

Gruß, Heiko

Offline MarkusL

  • Aktives Mitglied
  • ***
  • Beiträge: 124
  • Geschlecht: Männlich
Re: Ideenfindung für Import
« Antwort #3 am: 25.09.12 - 15:14:14 »
Danke an Klaus und Heiko. Werde eure Vorschläge mal testweise umsetzen.

Es lohnt sich immer wieder, dieses Forum zu nutzen.

Gruß Markus
Version Lotus Notes / Domino: 8.5.3
Server: 1 Cluster, 1 weiterer Server
Anzahl Benutzer: ca. 230

Offline koehlerbv

  • Moderator
  • Gold Platin u.s.w. member:)
  • *****
  • Beiträge: 20.460
  • Geschlecht: Männlich
Re: Ideenfindung für Import
« Antwort #4 am: 25.09.12 - 22:13:45 »
Nach meiner bescheidenen Meinung zielt Klaus auf die einfachere und naheliegendere Lösung:

- Hole Dir die erste Excel-Zeile
- Prüfe mit einer dafür vorgesehenen oder sowieso schon verwendbaren Ansicht, ob es bereits ein Dokument mit Deinen beiden Schlüssel gibt (alternativ - wenn Du an der DB nix ändern kannst / willst: db.Search, da es sich ja auch nur 500 Zeilen handelt und das nur halbjährlich passiert)
- Wenn nicht: Neues Dokument anlegen. Easy.
- Wenn doch: Spalte für Spalte die Werte durchgehen und mit bestehendem Dokument vergleichen. Identisch - vergessen. Nicht identisch: Item im Dokument ändern, boolesche Variable bSaveDocument auf True setzen.
- Durchlauf Spalte für Spalte beendet: Steht bSaveDocument auf True? Dokument speichern und bSaveDocument wieder auf False
- Nächste Zeile des Excel-Dokuments durchgehen ...

Das geht sehr fix, und mit diesem Verfahren kannst Du den gesamten Lauf jederzeit wiederholen.

Alles klar?

Bernhard

Offline gstueb

  • Aktives Mitglied
  • ***
  • Beiträge: 125
  • Geschlecht: Männlich
  • God is real unless declared integer
Re: Ideenfindung für Import
« Antwort #5 am: 25.09.12 - 23:36:36 »
an mich ist die Bitte herangetragen worden, eine Excel-Tabelle durch eine Notes-DB abzulösen, da hierdurch viele Vorteile gegeben sind.
Im Moment steht der Umsetzung gedanklich nur ein unregelmäßiger Import von Daten aus einer txt-Datei entgegen.
In der Datenbank sind derzeit ca. 4.500 Datensätze.
Bei jedem ca. halbjährlichen Import kommen ca. 300 - 500 Datensätze hinzu.
Bei dem Import müsste anhand von einer eindeutigen Kundennummer und einer weiteren eindeutigen Nummer geprüft werden, ob dieser Datensatz bereits existiert.

Hallo Markus,

für den Test, ob ein Dokument bereits vorhanden ist, könntest Du Dir eine spezielle Ansicht basteln. Diese sollte in der ersten Spalte eine Kombination aus Kundennummer und der anderen eindeutigen Nummer enthalten. Angenommen, die beiden Nummern wären numerisch und maximal 10 Stellen lang, dann könntest Du Dir in der Ansicht einen String daraus machen, so dass aus der KDNR 123456789 und der anderen Nummer 63050000 z.B. der String "01234567890063050000" in der ersten Spalte wird.

Im Agent, welcher die TXT-Datei einließt würde ich wie folgt vorgehen

Code
Alle Dokumente durchgehen und z.B. das Feld bearbeitung="" setzen.
Lese TextDatei
     Bilde SuchString aus Kundennummer und anderer eindeutigen Nummer aus TextDatei
     Über view.GetDocumentByKey(Suchstring) prüfen, ob Dokument existiert
     Dokument existiert
           ja --> Änderungen vornehmen
          feld bearbeitung auf "geändert" setzen
     Dokument existiert nicht
          Dokument anlegen und mit Werten füllen
          feld bearbeitung auf "neu" setzen
Ende Lese TextDatei

Über das (optionale) Feld "bearbeitung" könntest Du dann noch Ansichten basteln, in denen nur alle geänderten / hinzugefügten Dokumente aufgelistet werden.

Ich kann Dir hier noch ein paar Code-Samples anhängen. Zum einen eine Klasse für das Einlesen von CSV-Dateien:

Code
Class CSVImport
	
	Public EOF As Boolean
	Public strDelimiter As String
	
	Sub New(strCSVFile As String, strDelimiter As String)
		Me.strDelimiter = strDelimiter
		Dim strFeldname As String
		Dim vFeldArray As Variant
		Dim i As Integer
		Me.EOF = False
		If Not FileExists(strCSVFile) Then
			Me.EOF = True
			Exit Sub
		End If
		fileNum% = FreeFile()
		Open strCSVFile For Input As fileNum%
		If EOF(fileNum%) Then
			Me.EOF = True
			Exit Sub
		End If
		Line Input #fileNum%, strZeile
		
		vFeldArray = Split(strZeile,strDelimiter)
		If UBound(vFeldArray) = 0 Then
			Me.EOF = True
			Exit Sub
		End If
		For i=LBound(vFeldArray) To UBound(vFeldArray)
			strFeldname = VereinfacheUeberschrift$(vFeldArray(i))
			strFeldliste(strFeldname) = i
		Next
		
	End Sub
	
	Sub ReadNext
		Line Input #fileNum%, strZeile
		vDatenArray = Split(strZeile, strDelimiter)
		If EOF(fileNum%) Then
			Me.EOF = True
			Close fileNum%
		End If
	End Sub
	
' Übergabe von Feldnummer oder Feldname, Rückgabe von Feldinhalt
	Function Feldwert(vFeld As Variant) As String
		Dim iFeldNummer As Integer
		Dim strFeldname As String
		Dim strFeldwert As String
		iFeldNummer = -1
		If DataType(vFeld) = 8 Then ' Feldname wurde übergeben
			strFeldname = vFeld
			strFeldname = VereinfacheUeberschrift$(strFeldname)
			If IsElement(strFeldliste(strFeldname)) Then
				iFeldNummer = strFeldliste(strFeldname)
			End If
		Else
			iFeldNummer = vFeld
		End If
		If iFeldNummer >= LBound(vDatenArray) And iFeldNummer <= UBound(vDatenArray) Then
			strFeldwert = vDatenArray(iFeldNummer)
			strFeldwert = VereinfacheDaten$(strFeldwert )
		Else
			strFeldwert = ""
		End If
		Feldwert = strFeldwert
	End Function
	
	
	Public Function FileExists(strFile As String) As Boolean
		FileExists = True
		Dim dummy As Long
		Err=0
		On Error Resume Next
		dummy = FileLen(strFile)
		If Err <> 0 Then
			FileExists = False
		End If
		On Error GoTo 0
	End Function
	
' Entferne Anführungszeichen, außerdem alles in groß
	Private Function VereinfacheUeberschrift$(Ueberschrift$)
		Dim src$(0)
		Dim fnd$(0)
		Dim rep$(0)
		Dim ret As Variant
		
		src$(0) = Ueberschrift$
		fnd$(0) = {"}
		rep$(0) = ""
		
		ret = Replace(src$,fnd$,rep$)
		VereinfacheUeberschrift$ = Trim(UCase(ret(0)))
	End Function
	
' Entferne Anführungszeichen und Zeilenumbrüche
	Private Function VereinfacheDaten$(Daten$)
		Dim src$(0)
		Dim fnd$(1)
		Dim rep$(1)
		Dim ret As Variant
		
		src$(0) = Daten$
		fnd$(0) = Chr$(10)+Chr$(13)
		fnd$(1) = {"}
		rep$(0) = " "
		rep$(1) = ""
		
		ret = Replace(src$,fnd$,rep$)
		VereinfacheDaten$ = ret(0)
	End Function
	
End Class

und dann noch ein Code-Gerüst für das eben beschriebene:

Code
Sub Initialize
	Dim obCSV As New CSVImport(strFilename, Chr$(9) )
	Do Until obCSV.EOF
		obCSV.ReadNext
		strSuche = Right$("0000000000" + obCSV.Feldwert("Kundennummer"),10)
		GoSub BearbeiteDoc	
	Loop
	Exit Sub
	
	' Pro gelesener CSV-Zeile 	
BearbeiteDoc:
	Set view = session.Currentdatabase.GetView( "AnsichtFuerSuche" )
  	Set doc = view.GetDocumentByKey ( strSuche, True )
  	If doc Is Nothing Then ' Dokument existiert nicht
                Set doc = New NotesDocument ( session.CurrentDatabase )
                doc.Form = "Maske"
  	  	doc.Feld1 = obCSV.Feldwert("Feld1")
  	  	doc.Feld2 = obCSV.Feldwert("Feld2")
        else
  	  	doc.Feld1 = obCSV.Feldwert("Feld1")
  	  	doc.Feld2 = obCSV.Feldwert("Feld2")
	End If
	Call doc.Save(True,False)
	Return
	
End Sub
« Letzte Änderung: 26.09.12 - 00:33:05 von gstueb »

Offline joan

  • Junior Mitglied
  • **
  • Beiträge: 60
Re: Ideenfindung für Import
« Antwort #6 am: 28.09.12 - 08:25:34 »
Hallo Markus,

Zitat
In der Datenbank sind derzeit ca. 4.500 Datensätze.
Bei jedem ca. halbjährlichen Import kommen ca. 300 - 500 Datensätze hinzu.
Bei dem Import müsste anhand von einer eindeutigen Kundennummer und einer weiteren eindeutigen Nummer geprüft werden, ob dieser Datensatz bereits existiert.
Wenn ja, soll der bestehende mit neuen Infos ergänzt werden,
wenn nein, soll der Datensatz neu angelegt werden.

Ich mache das performanceoptimiert so:

1. Der Import liest per OLE die Excel Zeilen ein. Vorher passiert noch (4.)

2. Über die gelesene Excel Zeile wird ein Hash-Wert berechnet, der zusätzlich zu den Daten im angelegten Dokument gespeichert wird (geht am einfachsten und schnellsten mit Evaluate("@Password(<geleseneZeile>)").

3. In der Datenbank gibt es eine versteckte Ansicht, die zwei Spalten hat: Erste Spalte ist eine eindeutige Kennung des Datensatzes (sortiert), also die Kundennummer + weitere Nummern. Die zweite Spalte ist der Hash Wert des Dokuments.

4. Als erstes im Import Agent läuft ein viewNavigator über diese Ansicht, holt sich die Werte per viewEntry.Columnvalues() und merkt sich alle Kombinationen in einer Liste: Hash(<eindeutiger Schlüssel>) = Hashwert. Das geht durch den viewNavigator rasend schnell, weil keine Dokumente gelesen werden, sondern nur auf den view Index zugegriffen wird. Dem kann man sicherheitshalber vorher noch ein view.Refresh() geben.

5. Nach jeder gelesenen Excel Zeile berechnet der Import Agent erst einmal den Hash Wert dieser Zeile und prüft, ob er in der Hash Liste aus (4) enthalten ist. Wenn ja, ist der Datensatz vorhanden und wurde nicht geändert, also nächster Datensatz. Wenn der Wert nicht gefunden wird, ist der Datensatz neu oder wurde geändert, also Datensatz per view.GetDocumentByKey(.., True) holen und aktualisieren bzw. neu anlegen. Nicht vergessen, den Hash Wert beim Update neu zu berechnen.

Das ganze ist extrem schnell, weil die Dokumente nur dann gelesen werden müssen, wenn an diesem Dokument auch tatsächlich Änderungen gemacht wurden. Wenn nur wenige Änderungen nötig sind, ist der Agent selbst bei großen Datenbanken schneller fertig, als man die Konsole aufrufen kann, um ihn zu kontrollieren... ;)  Die einzig bremsende Komponente bei dem Verfahren ist nur noch der OLE Zugriff. Wenn man den durch Textdateien ersetzt, wird das ganze noch einmal ein gutes Stück schneller. Das würde ich vor allem dann machen, wenn größere Änderungen zu erwarten sind.

Offline Peter Klett

  • Gold Platin u.s.w. member:)
  • *****
  • Beiträge: 2.713
  • Geschlecht: Männlich
Re: Ideenfindung für Import
« Antwort #7 am: 28.09.12 - 12:18:14 »
Ganz interessanter Ansatz. Es darf nur nicht bei zwei unterschiedlichen Datensätzen der gleiche Hashwert herauskommen, was man bei dokumentenbasierten Anwendungen, für die Notes ideal ist, nicht zwingend ausschließen kann. In diesem Fall mit einer eindeutiger Nummer, also eher einem relationalen Ansatz, stellt das natürlich kein Problem dar.

Offline joan

  • Junior Mitglied
  • **
  • Beiträge: 60
Re: Ideenfindung für Import
« Antwort #8 am: 28.09.12 - 14:06:54 »
Hallo Peter,

Der Ansatz stammt nicht von mir - die Idee habe ich von Andrew Pollack, der das auf dem Entwickler-Camp schon des öfteren beschrieben hat. Die meisten kennen vermutlich seine Story, wie er damit einen Datenbankserver in die Knie gezwungen hat... ;)

Zitat
Es darf nur nicht bei zwei unterschiedlichen Datensätzen der gleiche Hashwert

Stimmt, die Wahrscheinlichkeit, dass das passiert, ist vorhanden, aber sie ist extrem gering. Die Algorithmen sind ja gerade darauf ausgelegt, daß das nach Möglichkeit nicht passiert. Und wer @Password mißtraut, kann natürlich auch einen eigenen Algorithmus implementieren, das ist dann halt langsamer. Ich habe das Verfahren seit Jahren in diversen Applikationen mit Millionen von Datensätzen und täglichen Updates im Einsatz und bisher kam es noch nie vor, dass ein Datensatz wegen zufälliger Gleichheit nicht aktualisiert wurde. So gesehen würde ich das Verfahren aus eigener Erfahrung als sicher bezeichnen.

Offline Peter Klett

  • Gold Platin u.s.w. member:)
  • *****
  • Beiträge: 2.713
  • Geschlecht: Männlich
Re: Ideenfindung für Import
« Antwort #9 am: 28.09.12 - 15:30:16 »
Nun, ich meinte, dass der Hashwert identisch ist, wenn auch die Daten identisch sind (nicht, dass er es bei ungleichen Daten sein kann).

Z.B. hast Du als Daten die Artikelnummer, die Kundennummer, die Anzahl und das Datum des Einkaufs

Jetzt kauft der Kunde am gleichen Tag den gleichen Artikel zweimal. Ist im Datum keine Uhrzeit enthalten, ist der Datensatz IDENTISCH, aber trotzdem zweimal da, und das auch berechtigt. Wenn Du dann beim Import mit der Routine Doppelimporte verhinderst, fehlt Dir ein Umsatz.

Offline joan

  • Junior Mitglied
  • **
  • Beiträge: 60
Re: Ideenfindung für Import
« Antwort #10 am: 28.09.12 - 15:36:26 »
Hallo Peter,

Ah, dann hatte ich flasch verstanden...

Klar, in solchen Fällen muss der Datensatz natürlich ein entsprechendes Unterscheidungsmerkmal enthalten.

 

Impressum Atnotes.de  -  Powered by Syslords Solutions  -  Datenschutz