changeset 0:834706423ac1

initial
author dwinter
date Tue, 26 Feb 2013 15:22:07 +0100
parents
children 9c356845613a
files .project .pydevproject .settings/org.eclipse.core.resources.prefs __init__.py test/test.py test/test2.py zopeSolr.py zpt/AddZopeSolr.zpt zpt/ChangeZopeSolr.zpt
diffstat 9 files changed, 560 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/.project	Tue Feb 26 15:22:07 2013 +0100
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+	<name>zopeSolr</name>
+	<comment></comment>
+	<projects>
+	</projects>
+	<buildSpec>
+		<buildCommand>
+			<name>org.python.pydev.PyDevBuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+	</buildSpec>
+	<natures>
+		<nature>org.python.pydev.pythonNature</nature>
+	</natures>
+</projectDescription>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/.pydevproject	Tue Feb 26 15:22:07 2013 +0100
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<?eclipse-pydev version="1.0"?><pydev_project>
+<pydev_pathproperty name="org.python.pydev.PROJECT_SOURCE_PATH">
+<path>/zopeSolr</path>
+</pydev_pathproperty>
+<pydev_property name="org.python.pydev.PYTHON_PROJECT_VERSION">python 2.7</pydev_property>
+<pydev_property name="org.python.pydev.PYTHON_PROJECT_INTERPRETER">pythonZope13</pydev_property>
+</pydev_project>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/.settings/org.eclipse.core.resources.prefs	Tue Feb 26 15:22:07 2013 +0100
@@ -0,0 +1,3 @@
+eclipse.preferences.version=1
+encoding/<project>=UTF-8
+encoding/zopeSolr.py=utf-8
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/__init__.py	Tue Feb 26 15:22:07 2013 +0100
@@ -0,0 +1,15 @@
+import zopeSolr
+
+def initialize(context):
+    """initialize OSAS"""
+
+    
+    context.registerClass(
+        zopeSolr.ZopeSolr,
+        constructors = (
+          zopeSolr.manage_addZopeSolrForm,
+          zopeSolr.manage_addZopeSolr
+          )
+        )
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/test.py	Tue Feb 26 15:22:07 2013 +0100
@@ -0,0 +1,30 @@
+'''
+Created on 11.02.2013
+
+@author: dwinter
+'''
+
+import sunburnt
+import httplib
+
+class TestSolr:
+    
+    solr = None
+    def __init__(self):
+         self.solr=sunburnt.SolrInterface(url="http://127.0.0.1:8983/solr/mpiwgweb")
+        
+if __name__ == '__main__':
+    
+    sl = TestSolr()
+    
+    #params={facet=true&facet.field=description&facet.field=main_content&start=0&q=main_content:knowledge+AND+renn+AND+description:*+AND+main_content:*&rows=10} hits=113 status=0 QTime=66 
+
+    x= {"qt":"tvrh","tv":"on","fl":"main_content","tv.tf":True}
+
+    fq = sl.solr.query(urlNorm="http://127.0.0.1:18080/www_neu/en/news/features/feature25",**x).facet_by("main_content")
+    x =  fq.execute()
+    
+    #http://localhost:8983/solr/mpiwgweb/select?q=*%3A*&wt=xml&tv=on&qt=tvrh&fl=main_content&tv.tf=true
+    #http://localhost:8983/solr/mpiwgweb/select?q=*%3A*&wt=json&tv=on&qt=tvrh&fl=main_content&tv.tf=true
+    print x.facet_counts.facet_fields['main_content']
+    
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/test2.py	Tue Feb 26 15:22:07 2013 +0100
@@ -0,0 +1,23 @@
+import httplib2
+import xml.etree.ElementTree as ET
+
+h = httplib2.Http()
+resp, content = h.request("http://localhost:8983/solr/mpiwgweb/select?q=*%3A*&wt=xml&tv=on&qt=tvrh&fl=main_content&tv.tf=true")
+
+root = ET.fromstring(content)
+uri = "http://127.0.0.1:18080/www_neu/de/aktuelles/features/feature28"
+fieldname="main_content"
+tvs = root.findall(".//lst[@name='termVectors']/lst[@name='%s']/lst[@name='%s']/lst"%(uri,fieldname))
+print tvs
+for tv in tvs:
+    word = tv.attrib['name']
+    for f in  tv.findall("./int[@name='tf']"):
+        fre = f.text
+        
+    print word,fre
+
+
+
+
+
+#<lst name="termVectors"><str name="uniqueKeyFieldName">urlNorm</str><lst name="http://127.0.0.1:18080/www_neu/de/aktuelles/features/feature28"><str name="uniqueKey">http://127.0.0.1:18080/www_neu/de/aktuelles/features/feature28</str><lst name="main_content"><lst name="1960er"><int name="tf">1</int></lst><lst name="1970er"><int name="tf">2</int></lst><lst name="1986">
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/zopeSolr.py	Tue Feb 26 15:22:07 2013 +0100
@@ -0,0 +1,436 @@
+# -*- coding: utf-8 -*-
+
+#Verbindet Zope mit solr. Vorraussetzung ist das Paket sunburnt, @see http://opensource.timetric.com/sunburnt/
+
+
+from OFS.SimpleItem import SimpleItem
+from Products.PageTemplates.PageTemplateFile import PageTemplateFile
+import pysolr
+import os.path
+import sunburnt
+from Globals import package_home
+import httplib2
+import urllib
+import re
+import xml.etree.ElementTree as ET
+import json
+   
+#Worte die nicht in der Termliste angezeigt werden sollen #TODO: make this configurable
+
+STOPLIST={'main_content':['forward','drucken','history','science','part','publications','projects',
+                          'project','new','geschichte','institute','related','boltzmannstraße','14195'],
+          
+          'title':['bd','10','11','12','18','19','20','abt','ad','di','history','geschichte','science']
+          }
+
+
+
+def zptFile(self, path, orphaned=False):
+    """returns a page template file from the product"""
+    if orphaned:
+        # unusual case
+        pt=PageTemplateFile(os.path.join(package_home(globals()), path))
+    else:
+      
+            pt=PageTemplateFile(os.path.join(package_home(globals()), path)).__of__(self)
+    return pt
+
+
+
+class ZopeSolr(SimpleItem):
+    
+    
+    meta_type="ZopeSolr"
+    
+    manage_options= ({'label':'Main Config','action': 'changeMain'},) + SimpleItem.manage_options
+    
+    def __init__(self,id,title,solrURL):
+        self.id=id 
+        self.title=title
+        self.solrURL=solrURL #URL einer solr instance bzw. einer collection, falls nicht die default collection benutzt werden soll
+        
+    
+    #Verbinde mit der solt Instance
+    
+    def connect(self):
+        self._v_solr=sunburnt.SolrInterface(url=self.solrURL)
+      
+    #erzeuge einen Link, insbesonder für faceted suche
+    #@param search: ist suchparameter, wird einfach als search=%s weitergereicht
+    #@param facetSearch: bekommt einen hash (feldname, liste der suchworte) 
+    
+    def generateLink(self,search,facetSearch={},ranges={}):
+        ret="?search=%s"%search
+       
+        for facet in facetSearch.keys():
+            
+            searchTerms = facetSearch[facet]
+            
+            if isinstance(searchTerms, basestring):
+                searchTerms=[searchTerms]
+                
+            for searchTerm in searchTerms:  
+                try:
+                    ret+="&%s_fc=%s"%(facet,searchTerm.encode('utf-8'))
+                except:
+                    ret+="&%s_fc=%s"%(facet,searchTerm)
+                
+        for key,values in ranges.items():
+            
+            if isinstance(values, basestring):
+                values=[values]
+            
+            for value in values:
+                ret+="&%s_rg=%s"%(key,value)    
+
+            
+        return ret
+        
+    #hilfsmethode erzeuget immer eine liste von einträgen
+    def getList(self,param):
+        if isinstance(param, basestring):
+            param=[param]
+         
+        return param
+        
+    #erzeugt analog zu den Ranges in Velocity für ein numerisches Feld die Suche in ranges  
+    #@param field:ist der name des Feldes in dem in Ranges gesucht werden soll
+    #@param begin anfang der ranges
+    #@param end ende der Raanges
+    #@param increment größe eines ranges
+    # für alle andere paramter @see prepareSearch
+    #@return gibt ein hash: mit range -> anzahl der Treffer in dem Ranage. e.g 1921-1950 -> 21
+    def ranges(self,field,begin,end,increment,solrQuery="",facetFields=[],start=0,rows=10,facetSearch=None,sortFacets=True):
+      
+        q=self.prepareSearch(solrQuery,facetFields,start,rows,facetSearch,sortFacets)
+   
+        res={}
+        if not getattr(self,'_v_solr_',None):
+            self.connect()
+        
+        
+    
+        for x in range(begin,end,increment):
+            query={}
+            #query["%s__gt"%field]=x
+            #TODO __gt scheint nicht zu funktionieren wird zu gte (???)
+            query["%s__gte"%field]=int(x)+1
+                       
+            query["%s__lte"%field]=x+increment
+            
+            result = q.query(**query).execute()
+            
+            res["%s-%s"%(x,x+increment)]=result.result.numFound
+            
+        return res
+            
+        
+    #prepareSearch erzeugt die Suchabfrage
+    
+    #solrQuery sucht im in schema.xml bzw. solrconfig.xml festgelegt generischen Feld, hierbei werden mit blanks getrennte eintrage in "AND" zerlegt.
+    #TODO: erlaube auch suche nach phrasen mit ""
+    #facetFields:Liste der Felder, nach denen facitiert werden sollen, wirdn in facet_by in solrburn uebersetzt.
+    #start: Erste Eintrag für paginierung, anzahl der Treffer
+    #rows: anzahl der Treffer
+    #facetSearch: Hash mit Feldnamen: suchwort  oder Feldname: liste von Suchworten, hast wird direkt an query von solrburnt weitergegeben,
+    #sortfacets: if true, dann werden die Ergebnisse der facetierten suche alphabetisch sortiert, ACHTUNG: das ist nicht gleich der Funktion in solr die Liste
+    #direkt sortiert zurückzubekommen, hier werden die haufigsten Werte genommen (einstellt in solrconfig.xml) und dann nur diese sortiert!
+    #ausserdem werden beim sortieren, die stopworte gefiltert!
+    #
+    #neben den direkten parameter koennen auch parameter fuer die facetierte Suche über FORM im REQUEST übergeben werden, diese Felder müssen dann
+    #mit "_fc" enden.
+    # gibt als ergebnis den folgenden Hash, so wie in http://opensource.timetric.com/sunburnt/queryingsolr.html#executing-queries-and-interpreting-the-response,
+    # http://opensource.timetric.com/sunburnt/queryingsolr.html#highlighting
+    # und http://opensource.timetric.com/sunburnt/queryingsolr.html#faceting
+    #dokumentiert. Highlighting selbst wird in sorlconfig.xml konfiguriert.
+    #return ein Queryobjet, zur eigentlichen Suche muss darauf noch execute ausgeführt werden.
+ 
+    def prepareSearch(self,solrQuery,facetFields=[],start=0,rows=10,facetSearch=None,sortFacets=True):
+        "search solr"
+      
+       
+        ranges={}
+        ## deal with a form   
+        if self.REQUEST:    
+            constr =  self.REQUEST.form
+            print constr
+            for field in constr.keys():
+              
+                #facetes
+                if field.endswith("_fc"):
+                    if facetSearch is None:
+                        facetSearch={}
+                    
+                    vals = constr[field]
+                    if not isinstance(vals,basestring):
+                      
+                        vals=[x.decode('utf-8') for x in vals]
+                    else:
+                        vals=vals.decode('utf-8')
+                    facetSearch[field.replace("_fc",'')]=vals
+                #ranges form a-b 
+                
+               
+                if field.endswith("_rg"):
+                    
+                    
+                    splitted = "_".split(field)
+                    if len(splitted)==2:
+                        #ranges[field.replace("_rg","__gt")]=splitted[0]
+                        #TODO __gt scheint nicht zu funktionieren wird zu gte (???)
+                        ranges[field.replace("_rg","__gte")]=int(splitted[0])+1
+                        ranges[field.replace("_rg","__lte")]=splitted[1]
+                    
+            
+        
+        #teste verbindung zu solr
+        if not getattr(self,'_v_solr_',None):
+            self.connect()
+        
+        
+        
+        solrQuery = solrQuery.decode('utf-8')
+        
+        #teile die suche nach " " daraus wird dann eine AND suche
+        #TODO: sollte flexibler sein. insbesondere phrasen
+        splitted= solrQuery.split(" ")
+        
+        res = self._v_solr
+        
+       
+        
+    
+        res=res.query(splitted)
+        if len(ranges.keys())>0:
+            res=res.query(ranges)
+         
+         
+        #ubergebe alle weiteren feld an die suche.
+        if facetSearch:
+            for key,vals in facetSearch.items():
+              
+                if key.endswith("_rg"):
+                
+                    if not isinstance(vals,basestring):
+                      
+                        vals=[x.decode('utf-8') for x in vals]
+                    else:
+                        vals=[vals.decode('utf-8')]
+                    
+                    for val in vals:
+                      
+                        splitted = val.split("-")
+                        print splitted
+                        if len(splitted)==2:
+                            #TODO __gt scheint nicht zu funktionieren wird zu gte (???)
+                            facetSearch[key.replace("_rg","__gte")]=int(splitted[0])+1
+                            facetSearch[key.replace("_rg","__lte")]=splitted[1]
+                            print "I AM HERE 3"
+                            print facetSearch
+                    del facetSearch[key] # loesche das urspuerngliche feld
+                    
+                else:
+                    val =  [x for x in vals if x!="*"]  #siehe oben
+                    facetSearch[key]=val
+            
+          
+            res=res.query(**facetSearch)
+        
+        
+        #wenn facetField existieren dann rufe facetierung auf
+        if len(facetFields)>0:
+            #for facet in facetFields:
+            
+            #    res = res.facet_by(facet)
+            res = res.facet_by(facetFields)
+                
+        #res=res.paginate(start=start, rows=rows).highlight("main_content")
+        
+        res=res.paginate(start=start, rows=rows)
+       
+       
+           
+        res=res.paginate(start=start, rows=rows).highlight()
+          
+        return res
+    
+    
+    #für die parameter @see prepareSearch
+    #erzeugt eine Suchabfrage und führt diese aus.
+    #return {"result":response.result, "hl":response.highlighting,"facetFields":facetedFields}   
+
+    def search(self,solrQuery,facetFields=[],start=0,rows=10,facetSearch=None,sortFacets=True):
+      
+        res=self.prepareSearch(solrQuery,facetFields,start,rows,facetSearch,sortFacets)
+        response= res.execute()
+            
+            #speichere faceted fields
+        if len(facetFields)>0:
+            facetedFields=response.facet_counts.facet_fields
+      
+            if sortFacets:
+                facetedFields=self.sortFacetedFields(facetedFields)
+              
+        else:
+            facetedFields={}
+        
+            
+        
+            
+        return {"result":response.result, "hl":response.highlighting,"facetFields":facetedFields}   
+        
+     
+     
+    #hilfsmethode zum sortieren über der ranges
+    def sortRanges(self,ranges):
+        x=list(ranges)
+        x.sort()
+        return x
+        
+    #sortiert die  Werte der FacetedFields 
+    #(facetedFields ist ein hast mit feldname -> liste der (wert für das feld, anzahl der treffer für den wert)
+    #ausserdem werden die werte gemäß des angegebenen Filter gefiltert.
+    
+    def sortFacetedFields(self, facetedFields,filter=STOPLIST):
+        ret={}
+        
+        def cmpTuple(x,y):
+            return cmp(x[0],y[0])
+            
+            
+        for key in facetedFields.keys():
+            ls = facetedFields[key]
+            ls.sort(cmpTuple)
+            ret[key]=ls
+            
+            if filter.get(key,None):
+                ls2=[]
+                for x in ls:
+                    if x[0].encode('utf-8') not in filter[key]:
+                        ls2.append(x)
+                ret[key]=ls2
+            
+            
+            ret[key]=[x for x in ret[key] if x[1]!=0]
+        return ret
+    
+    def changeMain(self,solrURL=None,title=None,REQUEST=None,RESPONSE=None):
+        """change main settings"""
+        if solrURL:
+            self.solrURL=solrURL
+            self.title=title  
+            self._v_solr=sunburnt.SolrInterface(url=solrURL)
+            
+            if RESPONSE is not None:
+                RESPONSE.redirect('manage_main')
+     
+     
+        else:
+            pt=zptFile(self, 'zpt/ChangeZopeSolr.zpt')
+            return pt()
+
+    #sucht die je nach einsteillung in solrconfig.xml Werte mit den häufigsten Treffern oder alphabetisch sortiert zu einem 
+    #bestimmten eintrag aus solr
+    #gedacht ist die methoden für die Anwendung nach dem Harvesten einer Website, es wird daher davon ausgegangen, dass sie hinter der
+    #idfield eine url steht. Wir es z.b. bei Nutch passiert. index.htm/index_html als Teil der url wird dabei unterdrückt (analog zu den harbest einstellunge für
+    # nutch für zope webseiten.
+    #@param @idfield is hierbei der Name des Feldes, das in solrschema als id defniert wurde
+    #field der Feldname von dem die Treffer gesurcht wernde sollen
+    #url die url des textes
+    
+    def getTermsAsJSON(self,idfield,field,url):
+        """getTerms"""
+        
+        ret=[]
+        h = httplib2.Http()
+        url = url.replace("/index.html","").replace("/index_html","")
+        if url[-1]=="/":
+            url=url[0:-1]
+            
+        urlq=url.replace(":","\:")
+        urlq=urlq.replace("/","\/")
+        
+        q ="http://localhost:8983/solr/mpiwgweb/select?q=%s:%s&wt=xml&tv=on&qt=tvrh&fl=%s&tv.tf=true"%(idfield,urlq,field)
+      
+        resp, content = h.request(q)
+       
+        root = ET.fromstring(content)
+        #uri = "http://127.0.0.1:18080/www_neu/de/aktuelles/features/feature28"
+        
+        xpstr = ".//lst[@name='termVectors']/lst[@name='%s']/lst[@name='%s']/lst"%(url,field)
+        
+       
+        tvs = root.findall(xpstr)
+
+        for tv in tvs:
+            wd = tv.attrib['name']
+            for f in  tv.findall("./int[@name='tf']"):
+                fre = f.text
+        
+            
+            if int(fre)>2:
+            
+                ret.append('{"text":"%s","size":%s}'%(wd,fre))
+        
+        retStr="["+",".join(ret)+"]"
+        
+        return retStr    
+    
+    #tauscht im request die in neewparams angegeben parameter aus.
+    def replaceParam(self, newparams):
+        x = self.REQUEST.form.copy()
+        
+        for key,value in newparams.items():
+            x[key]=value
+        
+       
+        retls=[]
+        for k,v in x.items():
+            if not isinstance(v,basestring):
+                for y in v:
+                    retls.append((k,y))
+            else:
+                retls.append((k,v))
+                
+        return "?"+"&".join(["%s=%s"%(k,urllib.quote_plus(v,'/')) for (k, v) in retls])
+        
+    
+    
+  
+    #ruft @set ranges aus, gibt das ergebnis als json zurück
+    def getRangesAsJSON(self,field,begin,end,increment): 
+        """ getRangesAsJSON"""
+        res = self.ranges(field, int(begin), int(end), int(increment))
+        return json.dumps(res)
+     
+        
+    #return only the values of resultList whicht start with startLetter or if starLetterNonAscii all values which
+    #start with an non ascii character
+    def filter (self,resultList,startLetter=None,startLetterNonAscii=0):
+        if startLetter:
+            
+            matchStr = "[\[\]'\"]*"+startLetter
+            ls = [x for x in resultList if re.match(matchStr,x[0])]
+        
+        if startLetterNonAscii ==1:
+           
+            ls = [x for x in resultList if not re.match("[\[\]'\"a-zA-Z].*",x[0])]
+        return ls
+        
+def manage_addZopeSolrForm(self):
+        """Form for external Links"""
+        pt=zptFile(self, 'zpt/AddZopeSolr.zpt')
+        return pt()
+
+
+def manage_addZopeSolr(self,id,title,solrURL,RESPONSE=None):
+    """Add an external Link"""
+
+    newObj=ZopeSolr(id,title,solrURL)
+
+    self._setObject(id,newObj)
+    
+  
+    if RESPONSE is not None:
+        RESPONSE.redirect('manage_main')
+        
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/zpt/AddZopeSolr.zpt	Tue Feb 26 15:22:07 2013 +0100
@@ -0,0 +1,14 @@
+<h1 tal:replace="structure here/manage_page_header">Header</h1>
+    <h2>Add a new Ressource</h2>
+    <form name="form" action="manage_addZopeSolr">
+    <table> 
+    	<tr><td> ID: </td><td><input type="text" name="id" size=50></td></tr>
+      <tr><td> Title: </td><td><input type="text" name="title" size=50></td></tr>
+      <tr><td> url: </td><td><input type="text" name="solrURL" size=50></td></tr>
+   
+    
+    </table>
+    <input type="submit" value="Change"><br/><br/>
+    </form>
+<h1 tal:replace="structure here/manage_page_footer">Footer</h1>
+    
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/zpt/ChangeZopeSolr.zpt	Tue Feb 26 15:22:07 2013 +0100
@@ -0,0 +1,14 @@
+<h1 tal:replace="structure here/manage_page_header">Header</h1>
+    <h2>Add a new Ressource</h2>
+    <form name="form" action="changeMain">
+    <table> 
+      <tr><td> Title: </td><td><input type="text" name="title" tal:attributes="value here/title" size=50></td></tr>
+      <tr><td> url: </td><td><input type="text" name="solrURL" tal:attributes="value here/solrURL" size=50></td></tr>
+   
+     
+    </table>
+    <input type="submit" value="Change"><br/><br/>
+    </form>
+    
+<h1 tal:replace="structure here/manage_page_footer">Footer</h1>
+    
\ No newline at end of file