2016-10-30 3 views
0

Ich habe eine Anwendung, wo ein Benutzer einen Namen eingibt und die aplication gibt die Adresse und Stadt für diesen Namen in DatenspeicherBessere Möglichkeit, Unterstrings in Datastore zu finden?

Die Namen sind zurück

class Person(ndb.Model): 
    name = ndb.StringProperty(repeated=True) 
    address = ndb.StringProperty(indexed=False) 
    city = ndb.StringProperty() 

Es gibt mehr als 5 Millionen von Personenentitäten. Namen können aus 2 bis 8 Wörtern gebildet werden (ja, es gibt Personen mit 8 Wörtern in seinen Namen)

Benutzer können beliebige Wörter für den Namen eingeben (in beliebiger Reihenfolge) und die Anwendung gibt die erste Übereinstimmung zurück. (" John Doe Smith“ist äquivalent zu‚Smith Doe John‘)

Dies ist ein Beispiel meiner Einheiten (die Art und Weise, wie wurde gesetzt (ndb.put_multi)

id="L12802795",nombre=["Smith","Loyola","Peter","","","","",""], city="Cali",address="Conchuela 471" 
id="M19181478",nombre=["Hoffa","Manzano","Linda","Rosse","Claudia","Cindy","Patricia",""], comuna="Lima",address="" 
id="L18793849",nombre=["Parker","Martinez","Claudio","George","Paul","","",""], comuna="Santiago",address="Calamar 323 Villa Los Pescadores" 

Dies ist die Art, wie ich den Namen bekommen vom Benutzer:

name = self.request.get('content').strip() #The input is the name (an string with several words) 
name=" ".join(name.split()).split() #now the name is a list of single words 

In meinem Entwurf, um einen Weg zu finden und Wörter im Namen für jede Entität suchen, habe ich dies getan.

 q = Person.query() 

     if len(name)==1: 
       names_query =q.filter(Person.name==name[0]) 
     elif len(name)==2: 
       names_query =q.filter(Person.name==name[0]).filter(Person.name==name[1]) 
     elif len(name)==3: 
        names_query =q.filter(Person.name==name[0]).filter(Person.name==name[1]).filter(Person.name==name[2]) 
     elif len(name)==4: 
       names_query =q.filter(Person.name==name[0]).filter(Person.name==name[1]).filter(Person.name==name[2]).filter(Person.name==name[3]) 
     elif len(name)==5: 
       names_query =q.filter(Person.name==name[0]).filter(Person.name==name[1]).filter(Person.name==name[2]).filter(Person.name==name[3]).filter(Person.name==name[4]) 
     elif len(name)==6: 
       names_query =q.filter(Person.name==name[0]).filter(Person.name==name[1]).filter(Person.name==name[2]).filter(Person.name==name[3]).filter(Person.name==name[4]).filter(Person.name==name[5]) 
     elif len(name)==7: 
       names_query =q.filter(Person.name==name[0]).filter(Person.name==name[1]).filter(Person.name==name[2]).filter(Person.name==name[3]).filter(Person.name==name[4]).filter(Person.name==name[5]).filter(Person.name==name[6]) 
     else : 
       names_query =q.filter(Person.name==name[0]).filter(Person.name==name[1]).filter(Person.name==name[2]).filter(Person.name==name[3]).filter(Person.name==name[4]).filter(Person.name==name[5]).filter(Person.name==name[6]).filter(Person.name==name[7]) 

     Person = names_query.fetch(1) 
     person_id=Person.key.id() 

Frage 1 Glauben Sie, dass, gibt es eine bessere Art und Weise Unter Strings in Strings (ndb.StringProperty) zum Suchen, in meinem Design. (Ich weiß, dass es funktioniert, aber ich glaube, es kann verbessert werden)

Frage 2 Meine Lösung hat ein Problem für Unternehmen mit repeted Worten im Namen.

Wenn ich eine Entität mit Wörtern "Smith Smith" finden will, bringt es mir "Paul Smith Wshite" statt "Paul Smith Smith", ich weiß nicht, wie ich meine Abfrage ändern kann, um 2 (oder mehr) zu finden) wiederholte Worte in Person.name

+0

In meinem Beispielcode ('Dies ist ein Beispiel für meine Entitäten (die Art und Weise wie (ndb.put_multi)') ** Ersetzen ** _ "nombre" _ für _ "name" _ und _ "comuna "_ for _" Stadt "_ um es zu verstehen. – fermaf

Antwort

2

Sie könnten eine Liste aller möglichen Token für jeden Namen generieren und Präfix Filter verwenden sie abfragen:

class Person(ndb.Model): 
    name = ndb.StringProperty(required=True) 
    address = ndb.StringProperty(indexed=False) 
    city = ndb.StringProperty() 

    def _tokens(self): 
    """Returns all possible combinations of name tokens combined. 

    For example, for input 'john doe smith' we will get: 
    ['john doe smith', 'john smith doe', 'doe john smith', 'doe smith john', 
    'smith john doe', 'smith doe john'] 
    """ 
    tokens = [t.lower() for t in self.name.split(' ') if t] 
    return [' '.join(t) for t in itertools.permutations(tokens)] or None 

    tokens = ndb.ComputedProperty(_tokens, repeated=True) 

    @classmethod 
    def suggest(cls, s): 
    s = s.lower() 
    return cls.query(ndb.AND(cls.tokens >= s, cls.tokens <= s + u'\ufffd')) 


ndb.put_multi([Person(name='John Doe Smith'), Person(name='Jane Doe Smith'), 
       Person(name='Paul Smith Wshite'), Person(name='Paul Smith'), 
       Person(name='Test'), Person(name='Paul Smith Smith')]) 
assert Person.suggest('j').count() == 2 
assert Person.suggest('ja').count() == 1 
assert Person.suggest('jo').count() == 1 
assert Person.suggest('doe').count() == 2 
assert Person.suggest('t').count() == 1 
assert Person.suggest('Smith Smith').get().name == 'Paul Smith Smith' 
assert Person.suggest('Paul Smith').count() == 3 

und stellen Sie sicher keys_only Abfragen verwenden, wenn Sie nur wollen Schlüssel/ids. Dies macht die Dinge in Bezug auf Datenspeicher-OPs wesentlich schneller und fast kostenlos.

+0

Vielen Dank @Dmytro Sadovnychyi, es ist eine kluge Lösung. (Ich nahm mich eine Weile, es zu verstehen, ich bin Neuling.) Aber es funktioniert nicht für Namen größer als 8 Worte (Es gibt mehr 40320 Permutationen, die größer als 1MB sind, also kann ich es nicht in den Datenspeicher setzen.) Für Namen mit weniger als 7 Worten funktioniert das. Ich habe den Austausch verbessert: return ['' .join (t) für t in iwertools .permutations (Tokens)] oder None für: m = ['' .join (t) für t in itertools.permutations (Tokens)] Rückgabeliste (set (l)) oder None – fermaf

+0

Danke @DmytroSadovnychyi – fermaf

+0

Sie sind herzlich willkommen! Bitte stellen Sie sicher, dass Sie die Antwort akzeptieren, wenn das Problem für Sie gelöst wurde. –

Verwandte Themen