Google App Engine: Gql LIKE sorgusu yapmak mümkün mü?


123

Gerçekten basit. SQL'de, bir metin alanında birkaç karakter aramak istersem, şunları yapabilirim:

SELECT blah FROM blah WHERE blah LIKE '%text%'

App Engine belgeleri bunun nasıl başarılacağından bahsetmiyor, ancak bu yeterince yaygın bir sorundur?


3
Devam eden sorun, GAE Datastore'u bir İlişkisel / ~ SQL veritabanıymış gibi kullanmaya çalışan insanların etrafında döner. Google'ın GQL'i tanıtmasıyla, insanları SQL sistemleri açısından düşünmeye yönlendiriyor. Ancak bunun doğru yaklaşım olduğundan emin olmasam da Google'ın geçişi herkes için çok daha kolay hale getirmeye çalıştığını anlıyorum.
fuentesjr

Yanıtlar:


81

App Engine için veritabanı arka ucu olan BigTable, milyonlarca kayda ölçeklenecek. Bu nedenle, App Engine, iyi doldurulmuş bir tablo için performans korkunç olacağından, tablo taramasıyla sonuçlanacak herhangi bir sorgu yapmanıza izin vermez.

Diğer bir deyişle, her sorgu bir dizin kullanmalıdır. Bu, yalnızca yapabileceği yüzden =, >ve <sorgular. (Aslında bunu da yapabilirsiniz, !=ancak API bunu bir >ve <sorgu kombinasyonunu kullanarak yapar .) Bu aynı zamanda geliştirme ortamının yaptığınız tüm sorguları izlemesi ve eksik dizinleri index.yamldosyanıza otomatik olarak eklemesinin nedenidir .

Bir LIKEsorgu için indekslemenin bir yolu yoktur, bu yüzden mevcut değildir.

Bunun çok daha iyi ve ayrıntılı bir açıklaması için bu Google IO oturumunu izleyin .


77

aynı sorunla karşı karşıyayım, ancak google uygulama motoru sayfalarında bir şey buldum:

İpucu: Sorgu filtrelerinin bir dize değerinin yalnızca bir kısmını eşleştirmek için açık bir yolu yoktur, ancak eşitsizlik filtrelerini kullanarak bir önek eşleşmesini taklit edebilirsiniz:

db.GqlQuery("SELECT * FROM MyModel WHERE prop >= :1 AND prop < :2",
            "abc",
            u"abc" + u"\ufffd")

Bu, her MyModel varlığını abc karakterleriyle başlayan bir string özellik propuyla eşleştirir. Unicode dizesi u "\ ufffd" olası en büyük Unicode karakterini temsil eder. Özellik değerleri bir dizinde sıralandığında, bu aralığa düşen değerler, verilen önekle başlayan değerlerin tümüdür.

http://code.google.com/appengine/docs/python/datastore/queriesandindexes.html

belki bu hile yapabilir;)


6
+1 Bunun büyük / küçük harfe duyarlı olduğunu belirtmekte fayda var. Neyse ki, sorguladığım alandaki veriler saklanmadan önce küçük harfe dönüştürülür.
Cuga

12

App Engine, LIKE sorgularını desteklemese de, ListProperty ve StringListProperty özelliklerine bir göz atın . Bu özellikler üzerinde bir eşitlik testi yapıldığında, test aslında tüm liste üyelerine uygulanacaktır, örneğin, list_property = valuedeğerin listenin herhangi bir yerinde görünüp görünmediğini test eder.

Bazen bu özellik, LIKE sorgularının olmamasına geçici bir çözüm olarak kullanılabilir. Örneğin, bu yazıda anlatıldığı gibi basit metin araması yapmayı mümkün kılar .


3
gönderi artık mevcut değil
mwm

9

SQL'e benzer tam metin arama sorguları gerçekleştirmek için arama hizmetini kullanmanız gerekir LIKE.

Gaelyk , daha kullanıcı dostu arama sorguları gerçekleştirmek için alana özgü dil sağlar . Örneğin, aşağıdaki kod parçası, başlığı içeren fern ve türe tam olarak uyan en son kitaplardan sıralanan ilk on kitabı bulacaktır thriller:

def documents = search.search {
    select all from books
    sort desc by published, SearchApiLimits.MINIMUM_DATE_VALUE
    where title =~ 'fern'
    and genre =  'thriller'
    limit 10
}

Like, Groovy'nin eşleştirme operatörü olarak yazılır =~. Bunun gibi işlevleri distance(geopoint(lat, lon), location)de destekler .



3

Burada Objectify'a bir göz atın , tıpkı bir Datastore erişim API'si gibidir. Özellikle bu soruyla ilgili bir SSS var, cevap burada

Benzer bir sorguyu nasıl yaparım ("foo%" GİBİ)
Saklandığında ve arandığında sırayı tersine çevirirseniz, startWith veya endWith gibi bir şey yapabilirsiniz. İstediğiniz başlangıç ​​değeriyle ve istediğiniz değerin hemen üstünde bir değerle bir aralık sorgusu yaparsınız.

String start = "foo";
    ... = ofy.query(MyEntity.class).filter("field >=", start).filter("field <", start + "\uFFFD");

1
"İçerir" değil "ile başlar" araması yapacaktır.
Hardik Patel

1

Burayı takip etmeniz yeterlidir: init.py # 354 "> http://code.google.com/p/googleappengine/source/browse/trunk/python/google/appengine/ext/search/ init .py # 354

İşe yarıyor!

class Article(search.SearchableModel):
    text = db.TextProperty()
    ...

  article = Article(text=...)
  article.save()

To search the full text index, use the SearchableModel.all() method to get an
instance of SearchableModel.Query, which subclasses db.Query. Use its search()
method to provide a search query, in addition to any other filters or sort
orders, e.g.:

  query = article.all().search('a search query').filter(...).order(...)

1

Bunu GAE Datastore düşük seviyeli Java API ile test ettim. Ben ve mükemmel çalışıyor

    Query q = new Query(Directorio.class.getSimpleName());

    Filter filterNombreGreater = new FilterPredicate("nombre", FilterOperator.GREATER_THAN_OR_EQUAL, query);
    Filter filterNombreLess = new FilterPredicate("nombre", FilterOperator.LESS_THAN, query+"\uFFFD");
    Filter filterNombre =  CompositeFilterOperator.and(filterNombreGreater, filterNombreLess);

    q.setFilter(filter);

1
bu önek için işe yarar, ancak dizenin sonundan itibaren eşleştirmek istersem ne olur? Örneğin - sdfdsabc'de abc'yi aramak istiyorum, sonra sdfdsabc döndürmeli
user1930106

1

Genel olarak, bu eski bir gönderi olsa da, bir 'LIKE' veya 'ILIKE' oluşturmanın bir yolu, bir '> =' sorgusundan tüm sonuçları toplamaktır, ardından döngü sonuçları, sizi içeren öğeler için python (veya Java) ile sonuçlanır. arıyoruz.

Aq = 'luigi' verilen kullanıcıları filtrelemek istediğinizi varsayalım.

users = []
qry = self.user_model.query(ndb.OR(self.user_model.name >= q.lower(),self.user_model.email >= q.lower(),self.user_model.username >= q.lower()))

for _qry in qry:
 if q.lower() in _qry.name.lower() or q.lower() in _qry.email.lower() or q.lower() in _qry.username.lower():
      users.append(_qry)

1

Datastore uygulama motorunda LIKE araması yapmak mümkün değildir, bir dizedeki bir kelimeyi aramanız gerekirse, bir Arraylist oluşturmanın işe yarayacağı bir gerçektir.

@Index
    public ArrayList<String> searchName;

ve sonra objectify kullanarak dizinde arama yapmak için.

List<Profiles> list1 = ofy().load().type(Profiles.class).filter("searchName =",search).list();

ve bu size aramada yaptığınız dünyayı içeren tüm öğelerin bir listesini verecektir.


0

Her LIKE '%text%'zaman bir veya birkaç kelimeyle karşılaştırılırsa (permütasyonları düşünün) ve verileriniz yavaşça değişirse (yavaş yavaş, endeksleri oluşturmak ve güncellemek için hem fiyat hem de performans açısından çok pahalı olmadığı anlamına gelir), o zaman İlişki Endeksi Varlığı (RIE) cevap olabilir.

Evet, ek veri deposu varlığı oluşturmanız ve uygun şekilde doldurmanız gerekecektir. Evet, etrafta oynamanız gereken bazı kısıtlamalar vardır (biri GAE veri deposundaki liste mülkünün uzunluğu için 5000 sınırdır). Ancak sonuçta ortaya çıkan aramalar yıldırım hızında.

Ayrıntılar için Java ile RIE ve Ojbectify ve Python gönderileri ile RIE'ye bakın .


0

"Beğen", genellikle metin aramanın yerine fakir bir adamın yerine kullanılır. Metin araması için Whoosh-AppEngine kullanmak mümkündür .

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.