Use STRSTARTS in fluent filter - sparql

I have troubles figuring out how to represent the following query in dotnetrdf using fluent query.
The SPARQL Query:
PREFIX a: <http://www.example.com/ex1#>
PREFIX rdf: < http://www.w3.org/1999/02/22-rdf-syntax-ns#>
SELECT ?object
WHERE {
a:Branch1 rdf:type ?object
FILTER(!STRSTARTS(STR(?object), "http://www.w3.org/2002/07/owl#"))
}
This is what I achieved so far, I couldn't figure the filter predicate.
var prefixes = new NamespaceMapper(true);
prefixes.AddNamespace("rdf", new Uri("http://www.w3.org/1999/02/22-rdf-syntax-ns#"));
prefixes.AddNamespace("a", new Uri("http://www.example.com/ex1#"));
var objVar = "object";
var queryBuilder =
QueryBuilder
.Select(new string[] { objVar })
.Where(
(triplePatternBuilder) =>
{
triplePatternBuilder
.Subject(element)
.PredicateUri("rdf:type")
.Object(objVar);
})
.Filter(f =>
// What should be added here?
);
queryBuilder.Prefixes = prefixes;
Thanks,

Unfortunately the STRSTARTS function hasn't been mapped to the fluent interface yet, but there is a way around that. You can build a regular ISparqlExpression in the Filter action and wrap it in a new BooleanExpression:
var queryBuilder =
QueryBuilder
.Select(new string[] { objVar })
.Where(
(triplePatternBuilder) =>
{
triplePatternBuilder
.Subject(element)
.PredicateUri("rdf:type")
.Object(objVar);
})
.Filter(f =>
new BooleanExpression(
new StrStartsFunction(
new StrFunction(new VariableTerm(objVar)),
f.Constant("http://www.w3.org/2002/07/owl#").Expression
))
);
NOTE: You may need to add VDS.RDF.Query.Builder.Expressions and VDS.RDF.Nodes to your imports for the above to compile.

Related

nHibernate Projections.Sum for joined columns

I am creating a query with Criteria like this:
DetachedCriteria auftragCriteria = DetachedCriteria.For<Auftrag>("a");
I join multiple tables with:
DetachedCriteria positionJoin = auftragCriteria.CreateCriteria("a.Positionen", "p", JoinType.LeftOuterJoin);
And I use a projection to fill in my object SubTypeAuftrag
ProjectionList projectionListSubTypeAuftrag = Projections.ProjectionList();
Now I need to recreate the following sql code:
cast(sum(p.length * p.width / 1000) as decimal)
I tried the following:
projectionListSubTypeAuftrag.Add(Projections.Sum<Position>(p => p.length * p.width / 1000), "M1");
This leads to an error:
System.InvalidOperationException: 'variable 'p' of type 'xxx.Base.Position' referenced from scope '', but it is not defined'
I also tried:
projectionListSubTypeAuftrag.Add(
Projections.Cast(
NHibernateUtil.Decimal,
Projections.SqlProjection("p.length * p.width/ 1000 AS result", new[] { "result" }, new IType[] { NHibernateUtil.Double })
),
"M1"
);
How can I tell nHibernate where to find the length/width column?
Maybee this will point you in the right direction.
var sqlMultiply = new VarArgsSQLFunction("(", "*", ")");
var sqlDivide = new VarArgsSQLFunction("(", "/", ")");
var multiplyLengthWidthProj = Projections.SqlFunction(sqlMultiply, NHibernateUtil.Decimal, Projections.Property(() => alias.Length), Projections.Property(() => alias.Width));
var sumProjection = Projections.ProjectionList().Add(Projections.Sum(Projections.SqlFunction(sqlDivide, NHibernateUtil.Decimal, multiplyLengthWidthProj, Projections.Constant(1000))));

Nhibernate SQLQuery as Subquery

How Can use a native sqlquery (session.CreateSqlQuery) as filtering subquery in another QueryOver:
// Get ids
var idsq = _session.CreateSQLQuery(
"select Id from [dbo].[SomeFunction](:parameter)")
.AddEntity(typeof(long)).
SetParameter("parameter", folderId);
// get entities by filtering where in (subquery)
MyEntity entityAlias = null;
var listOfEntities = await _session.QueryOver(() => entityAlias).
Where(x=>x.Id).IsIn(idsq).
OrderBy(x => x.Name).Asc.
ListAsync(cancelToken).ConfigureAwait(false);
You can't easily mix various styles of NHibernate... What you can do:
var crit = new SQLCriterion(SqlString.Parse("{alias}.Id IN (select Id from [dbo].[SomeFunction](?))"),
new object[] { folderId },
new IType[] { NHibernateUtil.Int64 });
and then:
var listOfEntities = await _session.QueryOver(() => entityAlias)
.Where(crit)
.OrderBy(x => x.Name).Asc
Note how I changed the text query adding {alias}.Id IN (...)

Work around for NEST not supporting pattern replace char filter

NEST doesn't appear to support the pattern replace char filter described here:
http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/analysis-pattern-replace-charfilter.html
I've created an issue at https://github.com/elasticsearch/elasticsearch-net/issues/543.
Most of my indexing is working so I would like to continue to use NEST. Is there a way I can work around this using some manual json injection at some point during the index configuration? I'm new to NEST so not sure if this is doable.
Specifically I'm hoping to use the pattern replace char filter to remove unit numbers from a street address before they are run through a custom analyzer (i.e. #205 - 1260 Broadway becomes 1260 Broadway). Because of the custom analyzer, I believe I need to use this char filter to accomplish this.
My current configuration looks like this:
elasticClient.CreateIndex("geocoding", c => c
.Analysis(ad => ad
.Analyzers(ab => ab
.Add("address-index", new CustomAnalyzer()
{
Tokenizer = "whitespace",
Filter = new List<string>() { "lowercase", "synonym" }
})
.Add("address-search", new CustomAnalyzer()
{
Tokenizer = "whitespace",
Filter = new List<string>() { "lowercase" },
CharFilter = new List<string>() { "drop-unit" }
})
)
.CharFilters(cfb => cfb
.Add("drop-unit", new CharFilter()) //missing char filter here
)
.TokenFilters(tfb => tfb
.Add("synonym", new SynonymTokenFilter()
{
Expand = true,
SynonymsPath = "analysis/synonym.txt"
})
)
)
UPDATE:
As of May 2014, NEST now supports the pattern replace char filter: https://github.com/elasticsearch/elasticsearch-net/pull/637
Instead of using the fluent settings during your index creation you can use the Settings.Add approach to add to the FluentDictionary in a more manual way, but with complete control over what settings are passed in. An example of this is shown in Create Index of the NEST Documentation. I am using this approach for a very similar reason.
You configuration would look something similar to the following:
elasticClient.CreateIndex("geocoding", c => c.
.Settings(s => s.
.Add("analysis.analyzer.address-index.type", "custom")
.Add("analysis.analyzer.address-index.tokenizer", "whitespace")
.Add("analysis.analyzer.address-index.filter.0", "lowercase")
.Add("analysis.analyzer.address-index.filter.1", "synonym")
.Add("anaylsis.analyzer.address-search.type", "custom")
.Add("analysis.analyzer.address-search.tokenizer", "whitespace")
.Add("analysis.analyzer.address-search.filter.0", "lowercase")
.Add("analysis.analyzer.address-search.char_filter.0", "drop-unit")
.Add("analysis.char_filter.drop-unit.type", "mapping")
.Add("analysis.char_filter.drop-unit.mappings.0", "<mapping1>")
.Add("analysis.char_filter.drop-unit.mappings.1", "<mapping2>")
...
)
);
You will need to replace <mapping1> and <mapping2> above with your actual char_filter mappings that you want to use. Please note that I have not used a char_filter before, so the settings values may be a little off, but should get you going in the right direction.
Just to provide a follow-up to Paige's very helpful answer, it looks like you can combine the fluent and manual Settings.Add approaches. The following worked for me:
elasticClient.CreateIndex("geocoding", c => c
.Settings(s => s
.Add("analysis.char_filter.drop_unit.type", "pattern_replace")
.Add("analysis.char_filter.drop_unit.pattern", #"#\d+\s-\s")
.Add("analysis.char_filter.drop_unit.replacement", "")
)
.Analysis(ad => ad
.Analyzers(ab => ab
.Add("address_index", new CustomAnalyzer()
{
Tokenizer = "whitespace",
Filter = new List<string>() { "lowercase", "synonym" }
})
.Add("address_search", new CustomAnalyzer()
{
CharFilter = new List<string> { "drop_unit" },
Tokenizer = "whitespace",
Filter = new List<string>() { "lowercase" }
})
)
.TokenFilters(tfb => tfb
.Add("synonym", new SynonymTokenFilter()
{
Expand = true,
SynonymsPath = "analysis/synonym.txt"
})
)
)
EsClient.CreateIndex("universal_de", c => c
.NumberOfReplicas(1)
.NumberOfShards(5)
.Settings(s => s //just as an example
.Add("merge.policy.merge_factor", "10")
.Add("search.slowlog.threshold.fetch.warn", "1s")
.Add("analysis.char_filter.drop_chars.type", "pattern_replace")
.Add("analysis.char_filter.drop_chars.pattern", #"[^0-9]")
.Add("analysis.char_filter.drop_chars.replacement", "")
.Add("analysis.char_filter.drop_specChars.type", "pattern_replace")
.Add("analysis.char_filter.drop_specChars.pattern", #"[^0-9a-zA-Z]")
.Add("analysis.char_filter.drop_specChars.replacement", "")
)
.Analysis(descriptor => descriptor
.Analyzers(bases => bases
.Add("folded_word", new CustomAnalyzer()
{
Filter = new List<string> { "lowercase", "asciifolding", "trim" },
Tokenizer = "standard"
}
)
.Add("trimmed_number", new CustomAnalyzer()
{
CharFilter = new List<string> { "drop_chars" },
Tokenizer = "standard",
Filter = new List<string>() { "lowercase" }
})
.Add("trimmed_specChars", new CustomAnalyzer()
{
CharFilter = new List<string> { "drop_specChars" },
Tokenizer = "standard",
Filter = new List<string>() { "lowercase" }
})
)
)
.AddMapping<Business>(m => m
//.MapFromAttributes()
.Properties(props => props
.MultiField(mf => mf
.Name(t => t.DirectoryName)
.Fields(fs => fs
.String(s => s.Name(t => t.DirectoryName).Analyzer("standard"))
.String(s => s.Name(t => t.DirectoryName.Suffix("folded")).Analyzer("folded_word"))
)
)
.MultiField(mf => mf
.Name(t => t.Phone)
.Fields(fs => fs
.String(s => s.Name(t => t.Phone).Analyzer("trimmed_number"))
)
)
This is how you create the index and add the mapping.
Now to search i have something like this :
var result = _Instance.Search<Business>(q => q
.TrackScores(true)
.Query(qq =>
{
QueryContainer termQuery = null;
if (!string.IsNullOrWhiteSpace(input.searchTerm))
{
var toLowSearchTerm = input.searchTerm.ToLower();
termQuery |= qq.QueryString(qs => qs
.OnFieldsWithBoost(f => f
.Add("directoryName.folded", 5.0)
)
.Query(toLowSearchTerm));
termQuery |= qq.Fuzzy(fz => fz.OnField("directoryName.folded").Value(toLowSearchTerm).MaxExpansions(2));
termQuery |= qq.Term("phone", Regex.Replace(toLowSearchTerm, #"[^0-9]", ""));
}
return termQuery;
})
.Skip(input.skip)
.Take(input.take)
);
NEW: I managed to use the pattern replace in a better way like this :
.Analysis(descriptor => descriptor
.Analyzers(bases => bases
.Add("folded_word", new CustomAnalyzer()
{
Filter = new List<string> { "lowercase", "asciifolding", "trim" },
Tokenizer = "standard"
}
)
.Add("trimmed_number", new CustomAnalyzer()
{
CharFilter = new List<string> { "drop_chars" },
Tokenizer = "standard",
Filter = new List<string>() { "lowercase" }
})
.Add("trimmed_specChars", new CustomAnalyzer()
{
CharFilter = new List<string> { "drop_specChars" },
Tokenizer = "standard",
Filter = new List<string>() { "lowercase" }
})
.Add("autocomplete", new CustomAnalyzer()
{
Tokenizer = new WhitespaceTokenizer().Type,
Filter = new List<string>() { "lowercase", "asciifolding", "trim", "engram" }
}
)
)
.TokenFilters(i => i
.Add("engram", new EdgeNGramTokenFilter
{
MinGram = 3,
MaxGram = 15
}
)
)
.CharFilters(cf => cf
.Add("drop_chars", new PatternReplaceCharFilter
{
Pattern = #"[^0-9]",
Replacement = ""
}
)
.Add("drop_specChars", new PatternReplaceCharFilter
{
Pattern = #"[^0-9a-zA-Z]",
Replacement = ""
}
)
)
)

codeigniter pagination for a query

So far found plenty of help to get the pagination working for a get(table) command.
What I need is to pick only few of the entries from a couple of linked tables based on a sql where statement.
I guess the query command is the one to use but in this case how do I do the pagination since that command does not take extra parameters such $config['per_page']
Thanks for the help
Without any more info to go on I think that what you're looking for is something like the following.
public function pagination_example($account_id)
{
$params = $this->uri->ruri_to_assoc(3, array('page'));
$where = array(
'account_id' => $account_id,
'active' => 1
);
$limit = array(
'limit' => 10,
'offset' => (!empty($params['page'])) ? $params['page'] : 0
);
$this->load->model('pagination_model');
$data['my_data'] = $this->pagination_model->get_my_data($where, $limit);
foreach($this->uri->segment_array() as $key => $segment)
{
if($segment == 'page')
{
$segment_id = $key + 1;
}
}
if(isset($segment_id))
{
$config['uri_segment'] = $segment_id;
}
else
{
$config['uri_segment'] = 0;
}
$config['base_url'] = 'http://'.$_SERVER['HTTP_HOST'].'/controller_name/method_name/whatever_your_other_parameters_are/page/';
$config['total_rows'] = $this->pagination_model->get_num_total_rows();// Make a method that will figure out the total number
$config['per_page'] = '10';
$this->load->library('pagination');
$this->pagination->initialize($config);
$data['pagination'] = $this->pagination->create_links();
$this->load->view('pagination_example_view', $data);
}
// pagination_model
public function get_my_data($where = array(), $limit = array())
{
$this->db
->select('whatever')
->from('wherever')
->where($where)
->limit($limit['limit'], $limit['offset']);
$query = $this->db->get();
if($query->num_rows() > 0)
{
$data = $query->result_array();
return $data;
}
return FALSE;
}
This should at least get you on the right track
If this isn't what you're asking I'd happy to help more if you can be a little more specific. How about some of your code.
The only other options that I can think of would be to either code a count in your select statement or not limit the query and use array_slice to select a portion of the returned array.

Disposing IDisposable items generated by Observable

I have an Observable<WebResponse> (WebResponse implements IDisposable)
responseObservable
.Where(webResponse => webResponse.ContentType.StartsWith("text/html"))
.Select(webResponse => webResponse.ContentLength)
.Run()
(Ignore the pointlessness of the query!)
so, I'm discarding WebResponse instances without calling Dispose on them. This seems bad.
More abstractly: If I have an Observable<IDisposable>, how do I deal with the disposal of generated items?
Assuming that you have a method WebResponse CreateMyWebResponse() use Observable.Using like this:
var responseObservable = Observable.Using(() => CreateMyWebResponse(), Observable.Return);
Change the Where and Do bits to something like
.Do(webResponse => {
if (webResponse.ContentType.StartsWith("text/html"))
ProcessAndDispose(webResponse);
else
webResponse.Dispose(); })
perhaps?
EDIT
Based on your edit, how about
.Select(webResponse => {
int r = -1;
if (webResponse.ContentType.StartsWith("text/html"))
r = webResponse.ContentLength;
webResponse.Dispose();
return r; })
.Where(i => i != -1)
now? This would generalize into something like
FilterProjectDispose(e, pred, proj) {
e.Select(x => {
using(x) {
if (pred(x)) return Some(proj(x));
else return None; }})
.Where(x => x.IsSome)
.Select(x => x.Value)
}
assuming Some/None as in F# (I am apparently starting to forget my C#).