How to combine a term query with a suggestion using Spring Data Elastic Search - spring-data-elasticsearch

I need to ensure that my suggestions come from documents with a particular join field.
I can create a term query:
QueryBuilder typeFilter = QueryBuilders.termQuery("joinField", "foo");
And I can run a search with suggestbuilder:
SuggestBuilder suggestBuilder = new SuggestBuilder();
suggestBuilder.addSuggestion("fieldname", SuggestBuilders
.phraseSuggestion("fieldname")
.text(searchTerm)
.size(10));
SearchSourceBuilder sourceBuilder = new SearchSourceBuilder()
sourceBuilder.suggest(suggestBuilder);
SearchRequest searchRequest = new SearchRequest("MyIndex")
searchRequest.source(sourceBuilder);
SearchResponse response = client.search(searchRequest, RequestOptions.DEFAULT);
But I can't see how to get suggestions only from documents returned by the termQuery.
NB "client" here is a RestHighLevelClient. I am using spring-data-elastic-search:4.1.5. NativeSearchQueryBuilder.withSuggestBuilder is not available to me because that was introduced in 4.3 and I am not able to upgrade

Looks like collateQuery is what I was looking for:
QueryBuilder typeFilter = QueryBuilders.termQuery("joinField", "foo");
SuggestBuilder suggestBuilder = new SuggestBuilder();
suggestBuilder.addSuggestion("fieldname", SuggestBuilders
.phraseSuggestion("fieldname")
.collateQuery(typeFilter.toString())
.text(searchTerm)
.size(10));

Related

Adwords API report segmenting

i'm trying to create google adwords report that will gain me
clicks,shows,cost,bounce,goal reach count
for each:
ad id, pharse id, goal id, day
(like group by)
There are a lot of different report types and i can't get how to create that kind of report.
Im using googleads-php-lib, so here is the code from example:
$selector = new Selector();
$selector->fields = array('Id', 'Clicks', 'Cost');
// Optional: use predicate to filter out paused criteria.
//$selector->predicates[] = new Predicate('Status', 'NOT_IN', array('PAUSED'));
// Create report definition.
$reportDefinition = new ReportDefinition();
$reportDefinition->selector = $selector;
$reportDefinition->reportName = 'Criteria performance report #' . uniqid();
$reportDefinition->dateRangeType = 'LAST_90_DAYS';
$reportDefinition->reportType = 'AD_PERFORMANCE_REPORT';
$reportDefinition->downloadFormat = 'CSV';
Sometimes you can't get all data in the same report. You can see all the report types in the AdWords Docs:
https://developers.google.com/adwords/api/docs/appendix/reports
You can add Segment in selector->fields
Example: ClickType is a segment so it will be implemented as given below.
$selector->fields = array('Id', 'Clicks', 'Cost', 'ClickType');
or with CriteriaReportWithAwql
$query = (new ReportQueryBuilder())
->select([
'CampaignId',
'CampaignName',
'Impressions',
'Clicks',
'Cost',
'ClickType',
'AccountCurrencyCode',
])
->from(ReportDefinitionReportType::CRITERIA_PERFORMANCE_REPORT)
->where('Status')->in(['ENABLED', 'PAUSED'])
->where('CampaignId')->in(['90045151'])
->during($startDate, $endDate)
->build();

How would I use Automapper in this query?

Given
Dim postviewmodel As IEnumerable(Of be_PostsViewModel)
postviewmodel = _postRepository.SelectAll.Select(Function(S) New
be_PostsViewModel With {.PostIsPublished = S.PostIsPublished, .Id =
S.PostId, .PostSummary = S.PostSummary, .PostDateCreated =
S.PostDateCreated,
.PostCategory = S.PostCategory, .PostTitle =
S.PostTitle}).Where(Function(p)
p.PostIsPublished = True).Where(Function(a) Not
a.PostCategory.FirstOrDefault.CategoryName = "Lead Story")
.Skip((Page - 1) * PageSize).Take(PageSize)
How would I use Automapper so I don't do all thmapping of properties by hand? I am completely new to it and have been doing a lot of reading but don't quite understand how to actually do it. I know I have to create the map and then call Mapper.map. But what goes where in Mapper.map?
I would do this:
Mapper.CreateMap<Post, be_postsViewModel>();
Do that in your application startup (App_Start etc). Then in your code above:
postViewModel = _postRepository.SelectAll.Project.To(Of be_PostsViewModel)
However, I'd put the "Project.To" AFTER all of your Where/Skip/Take pieces. The projection is the last thing you want to do. Project.To creates that exact Select expression, passes it to the query provider to modify the SQL at its base.
Unless SelectAll doesn't return IQueryable, then you have other, larger problems.

How to use having() in tableGateway in ZF2

How to use having() clause in ZF2?
There is almost no examples on the web how to prepare correct select object with having.
I have query like:
SELECT root_schema_id as `schema_id`
FROM `standard_specific_root_schemas`
WHERE `vehicle_id` IN (".implode(",",$vehiclesIds).")
GROUP BY `schema_id`, rootSubGroup_id HAVING count(*)=".$noOfVehicles
And I'm trying to run it in ZF2:
public function getVehicleWithinCommonRootSubgroupInSpecific($vehiclesIds)
{
$where = new Where();
$where->in('vehicle_id', $vehiclesIds);
$having = new Having('count(*) = '.count($vehiclesIds));
$rowset = $this->tableGateway->select(function (Select $select) use ($where, $having) {
$select
->where($where)
->having($having);
});
if (!$rowset) {
throw new \Exception("Could not find schemas for group $groupId");
}
return $rowset;
}
Of course that part in ZF2 is not finished yet as I wanted to check if it's working first.
I've tried few ways of providing params to having method but everything generates errors.
Help please, I'm desperate...
I cannot test your query, but can try and reproduce the query you need.
I adjusted the having to use ->expression() instead of a variable via the construct.
I also added the group statement.
To view the query I added a var_dump:
$where = new \Zend\Db\Sql\Where();
$where->in('vehicle_id', $vehiclesIds);
$having = new \Zend\Db\Sql\Having();
$having->expression('count(*) = ?', count($vehiclesIds));
$rowset = $this->tableGateway->select(function (\Zend\Db\Sql\Select $select) use ($where, $having) {
$select
->where($where)
->group(array('schema_id', 'rootSubGroup_id'))
->having($having);
var_dump( $select->getSqlString() );
});
Let me know if this helps.
To circumvent the error mentioned in the comments you would have to do something like below:
$sql = $this->tableGateway->getSql();
$select = $sql->select();
$where = new \Zend\Db\Sql\Where();
$where->in('vehicle_id', $vehiclesIds);
$having = new \Zend\Db\Sql\Having();
$having->expression('count(*) = ?', count($vehiclesIds));
$select
->where($where)
->group(array('schema_id', 'rootSubGroup_id'))
->having($having);
$preparedQuery = $sql->prepareStatementForSqlObject($select);
var_dump( $preparedQuery->getSql() );
However, if I'm right, the tableGateway does this for you so the error should go away once you start using the select to query the database.
Also, you can use the above to do that too, just replace this:
$preparedQuery = $sql->prepareStatementForSqlObject($select);
var_dump( $preparedQuery->getSql() );
With:
$this->tableGateway->selectWith($select);

Search a collection of objects

I'm trying to search for a collection of potential nodes but unable to do it...
I have a product that has a relationship with many instances. I would like to query the DB and get all the instances that are in a list that i get from the user.
Cypher:
var query = _context
.Cypher
.Start(new
{
instance = startBitsList,
product = productNode.Reference,
})
.Match("(product)-[:HasInstanceRel]->(instance)")
.Return(instance => instance.Node<ProductInstance>());
The problem is startBitsList... I use StringBuilder to generate a query that contains all the instances I'm looking for:
private static string CreateStartBits(IEnumerable<string> instanceNames)
{
var sb = new StringBuilder();
sb.AppendFormat("node:'entity_Name_Index'(");
foreach (var id in productIds)
{
sb.AppendFormat("Name={0} OR ", id);
}
sb.Remove(sb.Length - 4, 4);
sb.Append(")");
var startBitsList = sb.ToString();
return startBitsList;
}
I get exceptions when trying to run this cypher...
Is there a better way to search for multiple items that are stored in the collection I get from the user?
OK, I think there are a couple of issues at play here, first I'm presuming you are using Neo4j 1.9 and not 2.0 - hence using the .Start.
Have you tried taking your query and running it in Neo4j? This should be your first port of call, typically it's easy to add a breakpoint on the .Results call and add a 'watch' for query.Query.DebugText.
However, I don't think you need to use the StartBits the way you are, I think you'd be better off filtering with a .Where as you already have the start point:
private static ICypherFluentQuery CreateWhereClause(ICypherFluentQuery query, ICollection<string> instanceNames)
{
query = query.Where((Instance instance) => instance.Name == instanceNames.First());
query = instanceNames.Skip(1).Aggregate(query, (current, localInstanceName) => current.OrWhere((Instance instance) => instance.Name == localInstanceName));
return query;
}
and your query becomes something like:
var prodReference = new NodeReference<Product>(2);
var query =
Client.Cypher
.ParserVersion(1, 9)
.Start(new {product = prodReference})
.Match("(product)-[:HasInstanceRel]->(instance)");
query = CreateWhereClause(query, new[] {"Inst2", "Inst1"});
var resultsQuery = query.Return(instance => instance.As<Node<Instance>>());
2 things of note
We're not using the indexes - there is no benefit to using them as you have the start point and traversing to the 'instances' is a simple process for Neo4j.
The 'CreateWhereClause' method will probably go wrong if you pass in an empty list :)
The nice thing about not using the indexes is that - because they are legacy - you are set up better for Neo4j 2.0

Entity Framework - Join on many to many

I have a simple many to many relationship and I am wondering how you get data out of it. Here is the setup
Tables
Media
Media_Keyword (many to many map)
Keyword
Here is the code I have:
public List<Keyword> GetFromMedia(int mediaID)
{
var media = (from m in Connection.Data.Media
where m.id == mediaID
select m).First();
var keys = (from k in media.Media_Keyword
select new Keyword {ID = k.Keywords.id, Name = k.Keywords.keyword});
return keys.ToList();
}
Is there a way to do this better?
Usually, I select right from the many-to-many map.
var keys = from k in Connection.Data.Media_Keyword
where k.MediaID == mediaID
select k.Keywords;
I've not used the entity framework specifically, but can't you just combine them like this?
public List<Keyword> GetFromMedia(int mediaID)
{
return (from m in Connection.Data.Media
from k in m.Media_Keyword
where m.id == mediaID
select new Keyword {ID = k.Keywords.id, Name = k.Keywords.keyword}).ToList();
}
Response to Kleinux (Don't know why i can't add a comment to your question)
Sure you can, but it's not necessarly a good things, because context giving you a new "keyword". Then, if you try to update this or something thinking that you will update, context gonna see it as a new keyword and would create a new one instead of updating it.
** UPDATE
Sorry for my english, i'm french, well not french but from Quebec. I'm giving my 110%!!

Resources